<commit_before>#ifndef resplunk_event_Events_HeaderPlusPlus
#define resplunk_event_Events_HeaderPlusPlus

#include "resplunk/util/TemplateImplRepo.hpp"

#include <cstdint>
#include <limits>
#include <type_traits>
#include <functional>
#include <memory>
#include <map>
#include <exception>
#include <stack>
#include <set>
#include <tuple>

namespace resplunk
{
	namespace event
	{
		struct Event;

		struct ListenerPriority final
		{
			using Priority_t = std::intmax_t;

			static constexpr Priority_t FIRST = std::numeric_limits<Priority_t>::min();
			static constexpr Priority_t LAST  = std::numeric_limits<Priority_t>::max();

			constexpr ListenerPriority() noexcept
			: priority{}
			{
			}
			constexpr ListenerPriority(Priority_t p) noexcept
			: priority{p}
			{
			}
			constexpr ListenerPriority(ListenerPriority const &) = default;
			ListenerPriority &operator=(ListenerPriority const &) = delete;
			constexpr ListenerPriority(ListenerPriority &&) = default;
			ListenerPriority &operator=(ListenerPriority &&) = delete;

			constexpr operator Priority_t() const noexcept
			{
				return priority;
			}

			friend constexpr bool operator==(ListenerPriority const &a, ListenerPriority const &b) noexcept
			{
				return a.priority == b.priority;
			}
			friend constexpr bool operator<(ListenerPriority const &a, ListenerPriority const &b) noexcept
			{
				return a.priority < b.priority;
			}

		private:
			Priority_t const priority;
		};

		template<typename EventT>
		struct EventProcessor
		{
			static_assert(std::is_base_of<Event, EventT>::value, "EventT must derive from Event");
			using E = EventT;
			EventProcessor(ListenerPriority priority = ListenerPriority{}) noexcept
			{
				listen(priority);
			}
			EventProcessor(EventProcessor const &) = delete;
			EventProcessor &operator=(EventProcessor const &) = delete;
			EventProcessor(EventProcessor &&) = delete;
			EventProcessor &operator=(EventProcessor &&) = delete;
			virtual ~EventProcessor() noexcept
			{
				ignore();
			}

		protected:
			void listen(ListenerPriority priority = ListenerPriority{}) noexcept
			{
				return E::listen(*this, priority);
			}
			void ignore() noexcept
			{
				return E::ignore(*this);
			}

		private:
			virtual void onEvent(E &e) const noexcept = 0;

			friend typename E::Registrar_t;
		};

		template<typename EventT>
		struct LambdaEventProcessor
		: EventProcessor<EventT>
		{
			using Lambda_t = std::function<void (EventT &e) /*const*/>;
			LambdaEventProcessor(Lambda_t l, ListenerPriority priority = ListenerPriority{}) noexcept
			: EventProcessor<EventT>(priority)
			, lambda(l)
			{
			}

		private:
			Lambda_t lambda;
			virtual void onEvent(EventT &e) const noexcept override
			{
				return lambda(e);
			}
		};

		template<typename EventT>
		struct EventReactor
		{
			static_assert(std::is_base_of<Event, EventT>::value, "EventT must derive from Event");
			using E = EventT;
			EventReactor(ListenerPriority priority = ListenerPriority{}) noexcept
			{
				listen(priority);
			}
			EventReactor(EventReactor const &) = delete;
			EventReactor &operator=(EventReactor const &) = delete;
			EventReactor(EventReactor &&) = delete;
			EventReactor &operator=(EventReactor &&) = delete;
			virtual ~EventReactor() noexcept
			{
				ignore();
			}

		protected:
			void listen(ListenerPriority priority = ListenerPriority{}) noexcept
			{
				return E::listen(*this, priority);
			}
			void ignore() noexcept
			{
				return E::ignore(*this);
			}

		private:
			virtual void onEvent(E const &e) noexcept = 0;

			friend typename E::Registrar_t;
		};

		template<typename EventT>
		struct LambdaEventReactor
		: EventReactor<EventT>
		{
			using Lambda_t = std::function<void (EventT const &e)>;
			LambdaEventReactor(Lambda_t l, ListenerPriority priority = ListenerPriority{})
			: EventReactor<EventT>(priority) noexcept
			, lambda(l)
			{
			}

		private:
			Lambda_t lambda;
			virtual void onEvent(EventT const &e) noexcept override
			{
				return lambda(e);
			}
		};

		template<typename EventT>
		struct EventRegistrar final
		{
			static_assert(std::is_base_of<Event, EventT>::value, "EventT must derive from Event");
			using E = EventT;
			using Processor = EventProcessor<EventT>;
			using Reactor = EventReactor<EventT>;
			EventRegistrar() = delete;

			static void listen(Processor const &p, ListenerPriority priority = ListenerPriority{}) noexcept
			{
				processors().emplace(priority, std::cref(p));
			}
			static void listen(Reactor &r, ListenerPriority priority = ListenerPriority{}) noexcept
			{
				reactors().emplace(priority, std::ref(r));
			}

			static void ignore(Processor const &p) noexcept
			{
				auto &procs = processors();
				for(auto it = procs.begin(); it != procs.end(); )
				{
					if(std::addressof(p) == std::addressof(it->second.get()))
					{
						it = procs.erase(it);
					}
					else ++it;
				}
			}
			static void ignore(Reactor &r) noexcept
			{
				auto &reacts = reactors();
				for(auto it = reacts.begin(); it != reacts.end(); )
				{
					if(std::addressof(r) == std::addressof(it->second.get()))
					{
						it = reacts.erase(it);
					}
					else ++it;
				}
			}

			static void process(E &e) noexcept
			{
				if(!e.shouldProcess())
				{
					return;
				}
				auto &procs = processors();
				for(auto it = procs.begin(); it != procs.end(); ++it)
				{
					it->second.get().onEvent(e);
				}
			}
			static void react(E const &e) noexcept
			{
				if(!e.shouldReact())
				{
					return;
				}
				auto &reacts = reactors();
				for(auto it = reacts.begin(); it != reacts.end(); ++it)
				{
					it->second.get().onEvent(e);
				}
			}

		private:
			struct Key final
			{
				Key() = delete;
			};
			using Processors_t = std::multimap<ListenerPriority, std::reference_wrapper<Processor const>>;
			using Reactors_t = std::multimap<ListenerPriority, std::reference_wrapper<Reactor>>;
			static Processors_t &processors() noexcept
			{
				return util::TemplateImplRepo::get<Key, Processors_t>();
			}
			static auto reactors() noexcept
			-> Reactors_t &
			{
				return util::TemplateImplRepo::get<Key, Reactors_t>();
			}
		};

		namespace impl
		{
			template<typename T, typename...>
			struct Unwrapper;
			template<typename T, typename First, typename... Rest>
			struct Unwrapper<T, First, Rest...> final
			{
				static_assert(std::is_base_of<Event, First>::value, "ParentT must derive from Event");
				using Next = Unwrapper<T, Rest...>;
				Unwrapper() = delete;
				static void process(T &t) noexcept
				{
					t.First::process();
					Next::process(t);
				}
				static void react(T const &t) noexcept
				{
					t.First::react();
					Next::react(t);
				}
			};
			template<typename T>
			struct Unwrapper<T> final
			{
				static_assert(std::is_base_of<Event, typename T::E>::value, "Only Event can be root");
				Unwrapper() = delete;
				static void process(T &t) noexcept
				{
				}
				static void react(T const &t) noexcept
				{
				}
			};
			using Guard_t = std::stack<std::set<std::type_index>>;
			struct ProcessKey final
			{
				ProcessKey() = delete;
			};
			struct ReactKey final
			{
				ReactKey() = delete;
			};
			struct PR
			{
				virtual ~PR() noexcept = default;
				virtual void process() noexcept = 0;
				virtual void react() const noexcept = 0;
			};
		}
		template<typename EventT, typename... ParentT>
		struct EventImplementor
		: virtual impl::PR
		, virtual ParentT...
		{
			using Unwrapper_t = impl::Unwrapper<EventImplementor, ParentT...>;
			using E = EventT;
			using Parents_t = std::tuple<ParentT...>;
			using EventImplementor_t = EventImplementor;
			using Processor_t = EventProcessor<EventT>;
			using Reactor_t = EventReactor<EventT>;
			using Registrar_t = EventRegistrar<EventT>;
			static constexpr bool MI = (sizeof...(ParentT) > 1);
			static constexpr bool ROOT = (sizeof...(ParentT) == 0);
			virtual ~EventImplementor() = 0;

			static void listen(Processor_t const &p, ListenerPriority priority = ListenerPriority{}) noexcept
			{
				return Registrar_t::listen(p, priority);
			}
			static void listen(Reactor_t &r, ListenerPriority priority = ListenerPriority{}) noexcept
			{
				return Registrar_t::listen(r, priority);
			}

			static void ignore(Processor_t const &p) noexcept
			{
				return Registrar_t::ignore(p);
			}
			static void ignore(Reactor_t &r) noexcept
			{
				return Registrar_t::ignore(r);
			}

			virtual void process() noexcept override
			{
				using namespace impl;
				Guard_t &guard = util::TemplateImplRepo::get<ProcessKey, Guard_t>();
				if(typeid(*this) == typeid(E))
				{
					guard.emplace();
					guard.top().emplace(typeid(E));
				}
				else if(guard.top().find(typeid(E)) != guard.top().end())
				{
					return;
				}
				else
				{
					guard.top().emplace(typeid(E));
				}

				Unwrapper_t::process(*this);
				Registrar_t::process(dynamic_cast<E &>(*this));

				if(typeid(*this) == typeid(E))
				{
					guard.pop();
				}
			}
			virtual void react() const noexcept override
			{
				using namespace impl;
				Guard_t &guard = util::TemplateImplRepo::get<ReactKey, Guard_t>();
				if(typeid(*this) == typeid(E))
				{
					guard.emplace();
					guard.top().emplace(typeid(E));
				}
				else if(guard.top().find(typeid(E)) != guard.top().end())
				{
					return;
				}
				else
				{
					guard.top().emplace(typeid(E));
				}

				Unwrapper_t::react(*this);
				Registrar_t::react(dynamic_cast<E const &>(*this));

				if(typeid(*this) == typeid(E))
				{
					guard.pop();
				}
			}

		private:
			EventImplementor() = default;
			friend EventT;
		};
		template<typename EventT, typename... ParentT>
		EventImplementor<EventT, ParentT...>::~EventImplementor<EventT, ParentT...>() = default;
	}
}

#endif
<commit_msg>Add util funcs to get event parents<commit_after>#ifndef resplunk_event_Events_HeaderPlusPlus
#define resplunk_event_Events_HeaderPlusPlus

#include "resplunk/util/TemplateImplRepo.hpp"

#include <cstdint>
#include <limits>
#include <type_traits>
#include <functional>
#include <memory>
#include <map>
#include <exception>
#include <stack>
#include <set>
#include <tuple>

namespace resplunk
{
	namespace event
	{
		struct Event;

		struct ListenerPriority final
		{
			using Priority_t = std::intmax_t;

			static constexpr Priority_t FIRST = std::numeric_limits<Priority_t>::min();
			static constexpr Priority_t LAST  = std::numeric_limits<Priority_t>::max();

			constexpr ListenerPriority() noexcept
			: priority{}
			{
			}
			constexpr ListenerPriority(Priority_t p) noexcept
			: priority{p}
			{
			}
			constexpr ListenerPriority(ListenerPriority const &) = default;
			ListenerPriority &operator=(ListenerPriority const &) = delete;
			constexpr ListenerPriority(ListenerPriority &&) = default;
			ListenerPriority &operator=(ListenerPriority &&) = delete;

			constexpr operator Priority_t() const noexcept
			{
				return priority;
			}

			friend constexpr bool operator==(ListenerPriority const &a, ListenerPriority const &b) noexcept
			{
				return a.priority == b.priority;
			}
			friend constexpr bool operator<(ListenerPriority const &a, ListenerPriority const &b) noexcept
			{
				return a.priority < b.priority;
			}

		private:
			Priority_t const priority;
		};

		template<typename EventT>
		struct EventProcessor
		{
			static_assert(std::is_base_of<Event, EventT>::value, "EventT must derive from Event");
			using E = EventT;
			EventProcessor(ListenerPriority priority = ListenerPriority{}) noexcept
			{
				listen(priority);
			}
			EventProcessor(EventProcessor const &) = delete;
			EventProcessor &operator=(EventProcessor const &) = delete;
			EventProcessor(EventProcessor &&) = delete;
			EventProcessor &operator=(EventProcessor &&) = delete;
			virtual ~EventProcessor() noexcept
			{
				ignore();
			}

		protected:
			void listen(ListenerPriority priority = ListenerPriority{}) noexcept
			{
				return E::listen(*this, priority);
			}
			void ignore() noexcept
			{
				return E::ignore(*this);
			}

		private:
			virtual void onEvent(E &e) const noexcept = 0;

			friend typename E::Registrar_t;
		};

		template<typename EventT>
		struct LambdaEventProcessor
		: EventProcessor<EventT>
		{
			using Lambda_t = std::function<void (EventT &e) /*const*/>;
			LambdaEventProcessor(Lambda_t l, ListenerPriority priority = ListenerPriority{}) noexcept
			: EventProcessor<EventT>(priority)
			, lambda(l)
			{
			}

		private:
			Lambda_t lambda;
			virtual void onEvent(EventT &e) const noexcept override
			{
				return lambda(e);
			}
		};

		template<typename EventT>
		struct EventReactor
		{
			static_assert(std::is_base_of<Event, EventT>::value, "EventT must derive from Event");
			using E = EventT;
			EventReactor(ListenerPriority priority = ListenerPriority{}) noexcept
			{
				listen(priority);
			}
			EventReactor(EventReactor const &) = delete;
			EventReactor &operator=(EventReactor const &) = delete;
			EventReactor(EventReactor &&) = delete;
			EventReactor &operator=(EventReactor &&) = delete;
			virtual ~EventReactor() noexcept
			{
				ignore();
			}

		protected:
			void listen(ListenerPriority priority = ListenerPriority{}) noexcept
			{
				return E::listen(*this, priority);
			}
			void ignore() noexcept
			{
				return E::ignore(*this);
			}

		private:
			virtual void onEvent(E const &e) noexcept = 0;

			friend typename E::Registrar_t;
		};

		template<typename EventT>
		struct LambdaEventReactor
		: EventReactor<EventT>
		{
			using Lambda_t = std::function<void (EventT const &e)>;
			LambdaEventReactor(Lambda_t l, ListenerPriority priority = ListenerPriority{})
			: EventReactor<EventT>(priority) noexcept
			, lambda(l)
			{
			}

		private:
			Lambda_t lambda;
			virtual void onEvent(EventT const &e) noexcept override
			{
				return lambda(e);
			}
		};

		template<typename EventT>
		struct EventRegistrar final
		{
			static_assert(std::is_base_of<Event, EventT>::value, "EventT must derive from Event");
			using E = EventT;
			using Processor = EventProcessor<EventT>;
			using Reactor = EventReactor<EventT>;
			EventRegistrar() = delete;

			static void listen(Processor const &p, ListenerPriority priority = ListenerPriority{}) noexcept
			{
				processors().emplace(priority, std::cref(p));
			}
			static void listen(Reactor &r, ListenerPriority priority = ListenerPriority{}) noexcept
			{
				reactors().emplace(priority, std::ref(r));
			}

			static void ignore(Processor const &p) noexcept
			{
				auto &procs = processors();
				for(auto it = procs.begin(); it != procs.end(); )
				{
					if(std::addressof(p) == std::addressof(it->second.get()))
					{
						it = procs.erase(it);
					}
					else ++it;
				}
			}
			static void ignore(Reactor &r) noexcept
			{
				auto &reacts = reactors();
				for(auto it = reacts.begin(); it != reacts.end(); )
				{
					if(std::addressof(r) == std::addressof(it->second.get()))
					{
						it = reacts.erase(it);
					}
					else ++it;
				}
			}

			static void process(E &e) noexcept
			{
				if(!e.shouldProcess())
				{
					return;
				}
				auto &procs = processors();
				for(auto it = procs.begin(); it != procs.end(); ++it)
				{
					it->second.get().onEvent(e);
				}
			}
			static void react(E const &e) noexcept
			{
				if(!e.shouldReact())
				{
					return;
				}
				auto &reacts = reactors();
				for(auto it = reacts.begin(); it != reacts.end(); ++it)
				{
					it->second.get().onEvent(e);
				}
			}

		private:
			struct Key final
			{
				Key() = delete;
			};
			using Processors_t = std::multimap<ListenerPriority, std::reference_wrapper<Processor const>>;
			using Reactors_t = std::multimap<ListenerPriority, std::reference_wrapper<Reactor>>;
			static Processors_t &processors() noexcept
			{
				return util::TemplateImplRepo::get<Key, Processors_t>();
			}
			static auto reactors() noexcept
			-> Reactors_t &
			{
				return util::TemplateImplRepo::get<Key, Reactors_t>();
			}
		};

		namespace impl
		{
			template<typename T, typename...>
			struct Unwrapper;
			template<typename T, typename First, typename... Rest>
			struct Unwrapper<T, First, Rest...> final
			{
				static_assert(std::is_base_of<Event, First>::value, "ParentT must derive from Event");
				using Next = Unwrapper<T, Rest...>;
				Unwrapper() = delete;
				static void process(T &t) noexcept
				{
					t.First::process();
					Next::process(t);
				}
				static void react(T const &t) noexcept
				{
					t.First::react();
					Next::react(t);
				}
				static auto parents(T &t) noexcept
				{
					return tuple_cat(std::tuple<First &>{t}, Next::parents(t));
				}
				static auto parents(T const &t) noexcept
				{
					return tuple_cat(std::tuple<First const &>{t}, Next::parents(t));
				}
			};
			template<typename T>
			struct Unwrapper<T> final
			{
				static_assert(std::is_base_of<Event, typename T::E>::value, "Only Event can be root");
				Unwrapper() = delete;
				static void process(T &t) noexcept
				{
				}
				static void react(T const &t) noexcept
				{
				}
				static auto parents(T &t) noexcept
				-> std::tuple<>
				{
					return {};
				}
				static auto parents(T const &t) noexcept
				-> std::tuple<>
				{
					return {};
				}
			};
			using Guard_t = std::stack<std::set<std::type_index>>;
			struct ProcessKey final
			{
				ProcessKey() = delete;
			};
			struct ReactKey final
			{
				ReactKey() = delete;
			};
			struct PR
			{
				virtual ~PR() noexcept = default;
				virtual void process() noexcept = 0;
				virtual void react() const noexcept = 0;
			};
		}
		template<typename EventT, typename... ParentT>
		struct EventImplementor
		: virtual impl::PR
		, virtual ParentT...
		{
			using Unwrapper_t = impl::Unwrapper<EventImplementor, ParentT...>;
			using E = EventT;
			using Parents_t = std::tuple<ParentT &...>;
			using ConstParents_t = std::tuple<ParentT const &...>;
			using EventImplementor_t = EventImplementor;
			using Processor_t = EventProcessor<EventT>;
			using Reactor_t = EventReactor<EventT>;
			using Registrar_t = EventRegistrar<EventT>;
			static constexpr bool MI = (sizeof...(ParentT) > 1);
			static constexpr bool ROOT = (sizeof...(ParentT) == 0);
			virtual ~EventImplementor() = 0;

			static void listen(Processor_t const &p, ListenerPriority priority = ListenerPriority{}) noexcept
			{
				return Registrar_t::listen(p, priority);
			}
			static void listen(Reactor_t &r, ListenerPriority priority = ListenerPriority{}) noexcept
			{
				return Registrar_t::listen(r, priority);
			}

			static void ignore(Processor_t const &p) noexcept
			{
				return Registrar_t::ignore(p);
			}
			static void ignore(Reactor_t &r) noexcept
			{
				return Registrar_t::ignore(r);
			}

			virtual void process() noexcept override
			{
				using namespace impl;
				Guard_t &guard = util::TemplateImplRepo::get<ProcessKey, Guard_t>();
				if(typeid(*this) == typeid(E))
				{
					guard.emplace();
					guard.top().emplace(typeid(E));
				}
				else if(guard.top().find(typeid(E)) != guard.top().end())
				{
					return;
				}
				else
				{
					guard.top().emplace(typeid(E));
				}

				Unwrapper_t::process(*this);
				Registrar_t::process(dynamic_cast<E &>(*this));

				if(typeid(*this) == typeid(E))
				{
					guard.pop();
				}
			}
			virtual void react() const noexcept override
			{
				using namespace impl;
				Guard_t &guard = util::TemplateImplRepo::get<ReactKey, Guard_t>();
				if(typeid(*this) == typeid(E))
				{
					guard.emplace();
					guard.top().emplace(typeid(E));
				}
				else if(guard.top().find(typeid(E)) != guard.top().end())
				{
					return;
				}
				else
				{
					guard.top().emplace(typeid(E));
				}

				Unwrapper_t::react(*this);
				Registrar_t::react(dynamic_cast<E const &>(*this));

				if(typeid(*this) == typeid(E))
				{
					guard.pop();
				}
			}

		private:
			EventImplementor() = default;
			friend EventT;
		};
		template<typename EventT, typename... ParentT>
		EventImplementor<EventT, ParentT...>::~EventImplementor<EventT, ParentT...>() = default;

		template<typename EventT, typename... ParentT>
		auto parents(EventImplementor<EventT, ParentT...> &e) noexcept
		-> typename std::remove_reference<decltype(e)>::type::Parents_t
		{
			return std::remove_reference<decltype(e)>::type::Unwrapper_t::parents(e);
		}
		template<typename EventT, typename... ParentT>
		auto parents(EventImplementor<EventT, ParentT...> const &e) noexcept
		-> typename std::remove_reference<decltype(e)>::type::ConstParents_t
		{
			return std::remove_reference<decltype(e)>::type::Unwrapper_t::parents(e);
		}
	}
}

#endif
<|endoftext|>


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

// For 64-bit file access (off_t = off64_t, lseek64, etc).
#define _FILE_OFFSET_BITS 64

#include "net/base/file_stream.h"

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>

#include "base/basictypes.h"
#include "base/callback.h"
#include "base/eintr_wrapper.h"
#include "base/file_path.h"
#include "base/logging.h"
#include "base/message_loop.h"
#include "base/string_util.h"
#include "base/waitable_event.h"
#include "base/worker_pool.h"
#include "net/base/net_errors.h"

// We cast back and forth, so make sure it's the size we're expecting.
COMPILE_ASSERT(sizeof(int64) == sizeof(off_t), off_t_64_bit);

// Make sure our Whence mappings match the system headers.
COMPILE_ASSERT(net::FROM_BEGIN   == SEEK_SET &&
               net::FROM_CURRENT == SEEK_CUR &&
               net::FROM_END     == SEEK_END, whence_matches_system);

namespace net {
namespace {

// Map from errno to net error codes.
int64 MapErrorCode(int err) {
  switch (err) {
    case ENOENT:
      return ERR_FILE_NOT_FOUND;
    case EACCES:
      return ERR_ACCESS_DENIED;
    default:
      LOG(WARNING) << "Unknown error " << err << " mapped to net::ERR_FAILED";
      return ERR_FAILED;
  }
}

// ReadFile() is a simple wrapper around read() that handles EINTR signals and
// calls MapErrorCode() to map errno to net error codes.
int ReadFile(base::PlatformFile file, char* buf, int buf_len) {
  // read(..., 0) returns 0 to indicate end-of-file.

  // Loop in the case of getting interrupted by a signal.
  ssize_t res = HANDLE_EINTR(read(file, buf, static_cast<size_t>(buf_len)));
  if (res == static_cast<ssize_t>(-1))
    return MapErrorCode(errno);
  return static_cast<int>(res);
}

// WriteFile() is a simple wrapper around write() that handles EINTR signals and
// calls MapErrorCode() to map errno to net error codes.  It tries to write to
// completion.
int WriteFile(base::PlatformFile file, const char* buf, int buf_len) {
  ssize_t res = HANDLE_EINTR(write(file, buf, buf_len));
  if (res == -1)
    return MapErrorCode(errno);
  return res;
}

// BackgroundReadTask is a simple task that reads a file and then runs
// |callback|.  AsyncContext will post this task to the WorkerPool.
class BackgroundReadTask : public Task {
 public:
  BackgroundReadTask(base::PlatformFile file, char* buf, int buf_len,
                     CompletionCallback* callback);
  ~BackgroundReadTask();

  virtual void Run();

 private:
  const base::PlatformFile file_;
  char* const buf_;
  const int buf_len_;
  CompletionCallback* const callback_;

  DISALLOW_COPY_AND_ASSIGN(BackgroundReadTask);
};

BackgroundReadTask::BackgroundReadTask(
    base::PlatformFile file, char* buf, int buf_len,
    CompletionCallback* callback)
    : file_(file), buf_(buf), buf_len_(buf_len), callback_(callback) {}

BackgroundReadTask::~BackgroundReadTask() {}

void BackgroundReadTask::Run() {
  int result = ReadFile(file_, buf_, buf_len_);
  callback_->Run(result);
}

// BackgroundWriteTask is a simple task that writes to a file and then runs
// |callback|.  AsyncContext will post this task to the WorkerPool.
class BackgroundWriteTask : public Task {
 public:
  BackgroundWriteTask(base::PlatformFile file, const char* buf, int buf_len,
                      CompletionCallback* callback);
  ~BackgroundWriteTask();

  virtual void Run();

 private:
  const base::PlatformFile file_;
  const char* const buf_;
  const int buf_len_;
  CompletionCallback* const callback_;

  DISALLOW_COPY_AND_ASSIGN(BackgroundWriteTask);
};

BackgroundWriteTask::BackgroundWriteTask(
    base::PlatformFile file, const char* buf, int buf_len,
    CompletionCallback* callback)
    : file_(file), buf_(buf), buf_len_(buf_len), callback_(callback) {}

BackgroundWriteTask::~BackgroundWriteTask() {}

void BackgroundWriteTask::Run() {
  int result = WriteFile(file_, buf_, buf_len_);
  callback_->Run(result);
}

}  // namespace

// CancelableCallbackTask takes ownership of the Callback.  This task gets
// posted to the MessageLoopForIO instance.
class CancelableCallbackTask : public CancelableTask {
 public:
  explicit CancelableCallbackTask(Callback0::Type* callback)
      : canceled_(false), callback_(callback) {}

  virtual void Run() {
    if (!canceled_)
      callback_->Run();
  }

  virtual void Cancel() {
    canceled_ = true;
  }

 private:
  bool canceled_;
  scoped_ptr<Callback0::Type> callback_;
};

// FileStream::AsyncContext ----------------------------------------------

class FileStream::AsyncContext {
 public:
  AsyncContext();
  ~AsyncContext();

  // These methods post synchronous read() and write() calls to a WorkerThread.
  void InitiateAsyncRead(
      base::PlatformFile file, char* buf, int buf_len,
      CompletionCallback* callback);
  void InitiateAsyncWrite(
      base::PlatformFile file, const char* buf, int buf_len,
      CompletionCallback* callback);

  CompletionCallback* callback() const { return callback_; }

  // Called by the WorkerPool thread executing the IO after the IO completes.
  // This method queues RunAsynchronousCallback() on the MessageLoop and signals
  // |background_io_completed_callback_|, in case the destructor is waiting.  In
  // that case, the destructor will call RunAsynchronousCallback() instead, and
  // cancel |message_loop_task_|.
  // |result| is the result of the Read/Write task.
  void OnBackgroundIOCompleted(int result);

 private:
  // Always called on the IO thread, either directly by a task on the
  // MessageLoop or by ~AsyncContext().
  void RunAsynchronousCallback();

  // The MessageLoopForIO that this AsyncContext is running on.
  MessageLoopForIO* const message_loop_;
  CompletionCallback* callback_;  // The user provided callback.

  // A callback wrapper around OnBackgroundIOCompleted().  Run by the WorkerPool
  // thread doing the background IO on our behalf.
  CompletionCallbackImpl<AsyncContext> background_io_completed_callback_;

  // This is used to synchronize between the AsyncContext destructor (which runs
  // on the IO thread and OnBackgroundIOCompleted() which runs on the WorkerPool
  // thread.
  base::WaitableEvent background_io_completed_;

  // These variables are only valid when background_io_completed is signaled.
  int result_;
  CancelableCallbackTask* message_loop_task_;

  bool is_closing_;

  DISALLOW_COPY_AND_ASSIGN(AsyncContext);
};

FileStream::AsyncContext::AsyncContext()
    : message_loop_(MessageLoopForIO::current()),
      callback_(NULL),
      background_io_completed_callback_(
          this, &AsyncContext::OnBackgroundIOCompleted),
      background_io_completed_(true, false),
      message_loop_task_(NULL),
      is_closing_(false) {}

FileStream::AsyncContext::~AsyncContext() {
  is_closing_ = true;
  if (callback_) {
    // If |callback_| is non-NULL, that implies either the worker thread is
    // still running the IO task, or the completion callback is queued up on the
    // MessageLoopForIO, but AsyncContext() got deleted before then.
    const bool need_to_wait = !background_io_completed_.IsSignaled();
    base::TimeTicks start = base::TimeTicks::Now();
    RunAsynchronousCallback();
    if (need_to_wait) {
      // We want to see if we block the message loop for too long.
      UMA_HISTOGRAM_TIMES("AsyncIO.FileStreamClose",
                          base::TimeTicks::Now() - start);
    }
  }
}

void FileStream::AsyncContext::InitiateAsyncRead(
    base::PlatformFile file, char* buf, int buf_len,
    CompletionCallback* callback) {
  DCHECK(!callback_);
  callback_ = callback;

  WorkerPool::PostTask(FROM_HERE,
                       new BackgroundReadTask(
                           file, buf, buf_len,
                           &background_io_completed_callback_),
                       true /* task_is_slow */);
}

void FileStream::AsyncContext::InitiateAsyncWrite(
    base::PlatformFile file, const char* buf, int buf_len,
    CompletionCallback* callback) {
  DCHECK(!callback_);
  callback_ = callback;

  WorkerPool::PostTask(FROM_HERE,
                       new BackgroundWriteTask(
                           file, buf, buf_len,
                           &background_io_completed_callback_),
                       true /* task_is_slow */);
}

void FileStream::AsyncContext::OnBackgroundIOCompleted(int result) {
  result_ = result;
  message_loop_task_ = new CancelableCallbackTask(
      NewCallback(this, &AsyncContext::RunAsynchronousCallback));
  message_loop_->PostTask(FROM_HERE, message_loop_task_);
  background_io_completed_.Signal();
}

void FileStream::AsyncContext::RunAsynchronousCallback() {
  // Wait() here ensures that all modifications from the WorkerPool thread are
  // now visible.
  background_io_completed_.Wait();

  // Either we're in the MessageLoop's task, in which case Cancel() doesn't do
  // anything, or we're in ~AsyncContext(), in which case this prevents the call
  // from happening again.  Must do it here after calling Wait().
  message_loop_task_->Cancel();
  message_loop_task_ = NULL;

  if (is_closing_) {
    callback_ = NULL;
    return;
  }

  DCHECK(callback_);
  CompletionCallback* temp = NULL;
  std::swap(temp, callback_);
  background_io_completed_.Reset();
  temp->Run(result_);
}

// FileStream ------------------------------------------------------------

FileStream::FileStream()
    : file_(base::kInvalidPlatformFileValue),
      open_flags_(0),
      auto_closed_(true) {
  DCHECK(!IsOpen());
}

FileStream::FileStream(base::PlatformFile file, int flags)
    : file_(file),
      open_flags_(flags),
      auto_closed_(false) {
  // If the file handle is opened with base::PLATFORM_FILE_ASYNC, we need to
  // make sure we will perform asynchronous File IO to it.
  if (flags & base::PLATFORM_FILE_ASYNC) {
    async_context_.reset(new AsyncContext());
  }
}

FileStream::~FileStream() {
  Close();
}

void FileStream::Close() {
  // Abort any existing asynchronous operations.
  async_context_.reset();

  if (file_ != base::kInvalidPlatformFileValue) {
    if (close(file_) != 0) {
      NOTREACHED();
    }
    file_ = base::kInvalidPlatformFileValue;
  }
}

int FileStream::Open(const FilePath& path, int open_flags) {
  if (IsOpen()) {
    DLOG(FATAL) << "File is already open!";
    return ERR_UNEXPECTED;
  }

  open_flags_ = open_flags;
  file_ = base::CreatePlatformFile(path, open_flags_, NULL);
  if (file_ == base::kInvalidPlatformFileValue) {
    LOG(WARNING) << "Failed to open file: " << errno
          << " (" << path.ToWStringHack() << ")";
    return MapErrorCode(errno);
  }

  if (open_flags_ & base::PLATFORM_FILE_ASYNC) {
    async_context_.reset(new AsyncContext());
  }

  return OK;
}

bool FileStream::IsOpen() const {
  return file_ != base::kInvalidPlatformFileValue;
}

int64 FileStream::Seek(Whence whence, int64 offset) {
  if (!IsOpen())
    return ERR_UNEXPECTED;

  // If we're in async, make sure we don't have a request in flight.
  DCHECK(!async_context_.get() || !async_context_->callback());

  off_t res = lseek(file_, static_cast<off_t>(offset),
                    static_cast<int>(whence));
  if (res == static_cast<off_t>(-1))
    return MapErrorCode(errno);

  return res;
}

int64 FileStream::Available() {
  if (!IsOpen())
    return ERR_UNEXPECTED;

  int64 cur_pos = Seek(FROM_CURRENT, 0);
  if (cur_pos < 0)
    return cur_pos;

  struct stat info;
  if (fstat(file_, &info) != 0)
    return MapErrorCode(errno);

  int64 size = static_cast<int64>(info.st_size);
  DCHECK_GT(size, cur_pos);

  return size - cur_pos;
}

int FileStream::Read(
    char* buf, int buf_len, CompletionCallback* callback) {
  if (!IsOpen())
    return ERR_UNEXPECTED;

  // read(..., 0) will return 0, which indicates end-of-file.
  DCHECK(buf_len > 0);
  DCHECK(open_flags_ & base::PLATFORM_FILE_READ);

  if (async_context_.get()) {
    DCHECK(open_flags_ & base::PLATFORM_FILE_ASYNC);
    // If we're in async, make sure we don't have a request in flight.
    DCHECK(!async_context_->callback());
    async_context_->InitiateAsyncRead(file_, buf, buf_len, callback);
    return ERR_IO_PENDING;
  } else {
    return ReadFile(file_, buf, buf_len);
  }
}

int FileStream::ReadUntilComplete(char *buf, int buf_len) {
  int to_read = buf_len;
  int bytes_total = 0;

  do {
    int bytes_read = Read(buf, to_read, NULL);
    if (bytes_read <= 0) {
      if (bytes_total == 0)
        return bytes_read;

      return bytes_total;
    }

    bytes_total += bytes_read;
    buf += bytes_read;
    to_read -= bytes_read;
  } while (bytes_total < buf_len);

  return bytes_total;
}

int FileStream::Write(
    const char* buf, int buf_len, CompletionCallback* callback) {
  // write(..., 0) will return 0, which indicates end-of-file.
  DCHECK(buf_len > 0);

  if (!IsOpen())
    return ERR_UNEXPECTED;

  if (async_context_.get()) {
    DCHECK(open_flags_ & base::PLATFORM_FILE_ASYNC);
    // If we're in async, make sure we don't have a request in flight.
    DCHECK(!async_context_->callback());
    async_context_->InitiateAsyncWrite(file_, buf, buf_len, callback);
    return ERR_IO_PENDING;
  } else {
    return WriteFile(file_, buf, buf_len);
  }
}

int64 FileStream::Truncate(int64 bytes) {
  if (!IsOpen())
    return ERR_UNEXPECTED;

  // We better be open for reading.
  DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE);

  // Seek to the position to truncate from.
  int64 seek_position = Seek(FROM_BEGIN, bytes);
  if (seek_position != bytes)
    return ERR_UNEXPECTED;

  // And truncate the file.
  int result = ftruncate(file_, bytes);
  return result == 0 ? seek_position : MapErrorCode(errno);
}

}  // namespace net
<commit_msg>Fix ~FileStream in POSIX to auto close if the flag is set. This is left from my last patch.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// For 64-bit file access (off_t = off64_t, lseek64, etc).
#define _FILE_OFFSET_BITS 64

#include "net/base/file_stream.h"

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>

#include "base/basictypes.h"
#include "base/callback.h"
#include "base/eintr_wrapper.h"
#include "base/file_path.h"
#include "base/logging.h"
#include "base/message_loop.h"
#include "base/string_util.h"
#include "base/waitable_event.h"
#include "base/worker_pool.h"
#include "net/base/net_errors.h"

// We cast back and forth, so make sure it's the size we're expecting.
COMPILE_ASSERT(sizeof(int64) == sizeof(off_t), off_t_64_bit);

// Make sure our Whence mappings match the system headers.
COMPILE_ASSERT(net::FROM_BEGIN   == SEEK_SET &&
               net::FROM_CURRENT == SEEK_CUR &&
               net::FROM_END     == SEEK_END, whence_matches_system);

namespace net {
namespace {

// Map from errno to net error codes.
int64 MapErrorCode(int err) {
  switch (err) {
    case ENOENT:
      return ERR_FILE_NOT_FOUND;
    case EACCES:
      return ERR_ACCESS_DENIED;
    default:
      LOG(WARNING) << "Unknown error " << err << " mapped to net::ERR_FAILED";
      return ERR_FAILED;
  }
}

// ReadFile() is a simple wrapper around read() that handles EINTR signals and
// calls MapErrorCode() to map errno to net error codes.
int ReadFile(base::PlatformFile file, char* buf, int buf_len) {
  // read(..., 0) returns 0 to indicate end-of-file.

  // Loop in the case of getting interrupted by a signal.
  ssize_t res = HANDLE_EINTR(read(file, buf, static_cast<size_t>(buf_len)));
  if (res == static_cast<ssize_t>(-1))
    return MapErrorCode(errno);
  return static_cast<int>(res);
}

// WriteFile() is a simple wrapper around write() that handles EINTR signals and
// calls MapErrorCode() to map errno to net error codes.  It tries to write to
// completion.
int WriteFile(base::PlatformFile file, const char* buf, int buf_len) {
  ssize_t res = HANDLE_EINTR(write(file, buf, buf_len));
  if (res == -1)
    return MapErrorCode(errno);
  return res;
}

// BackgroundReadTask is a simple task that reads a file and then runs
// |callback|.  AsyncContext will post this task to the WorkerPool.
class BackgroundReadTask : public Task {
 public:
  BackgroundReadTask(base::PlatformFile file, char* buf, int buf_len,
                     CompletionCallback* callback);
  ~BackgroundReadTask();

  virtual void Run();

 private:
  const base::PlatformFile file_;
  char* const buf_;
  const int buf_len_;
  CompletionCallback* const callback_;

  DISALLOW_COPY_AND_ASSIGN(BackgroundReadTask);
};

BackgroundReadTask::BackgroundReadTask(
    base::PlatformFile file, char* buf, int buf_len,
    CompletionCallback* callback)
    : file_(file), buf_(buf), buf_len_(buf_len), callback_(callback) {}

BackgroundReadTask::~BackgroundReadTask() {}

void BackgroundReadTask::Run() {
  int result = ReadFile(file_, buf_, buf_len_);
  callback_->Run(result);
}

// BackgroundWriteTask is a simple task that writes to a file and then runs
// |callback|.  AsyncContext will post this task to the WorkerPool.
class BackgroundWriteTask : public Task {
 public:
  BackgroundWriteTask(base::PlatformFile file, const char* buf, int buf_len,
                      CompletionCallback* callback);
  ~BackgroundWriteTask();

  virtual void Run();

 private:
  const base::PlatformFile file_;
  const char* const buf_;
  const int buf_len_;
  CompletionCallback* const callback_;

  DISALLOW_COPY_AND_ASSIGN(BackgroundWriteTask);
};

BackgroundWriteTask::BackgroundWriteTask(
    base::PlatformFile file, const char* buf, int buf_len,
    CompletionCallback* callback)
    : file_(file), buf_(buf), buf_len_(buf_len), callback_(callback) {}

BackgroundWriteTask::~BackgroundWriteTask() {}

void BackgroundWriteTask::Run() {
  int result = WriteFile(file_, buf_, buf_len_);
  callback_->Run(result);
}

}  // namespace

// CancelableCallbackTask takes ownership of the Callback.  This task gets
// posted to the MessageLoopForIO instance.
class CancelableCallbackTask : public CancelableTask {
 public:
  explicit CancelableCallbackTask(Callback0::Type* callback)
      : canceled_(false), callback_(callback) {}

  virtual void Run() {
    if (!canceled_)
      callback_->Run();
  }

  virtual void Cancel() {
    canceled_ = true;
  }

 private:
  bool canceled_;
  scoped_ptr<Callback0::Type> callback_;
};

// FileStream::AsyncContext ----------------------------------------------

class FileStream::AsyncContext {
 public:
  AsyncContext();
  ~AsyncContext();

  // These methods post synchronous read() and write() calls to a WorkerThread.
  void InitiateAsyncRead(
      base::PlatformFile file, char* buf, int buf_len,
      CompletionCallback* callback);
  void InitiateAsyncWrite(
      base::PlatformFile file, const char* buf, int buf_len,
      CompletionCallback* callback);

  CompletionCallback* callback() const { return callback_; }

  // Called by the WorkerPool thread executing the IO after the IO completes.
  // This method queues RunAsynchronousCallback() on the MessageLoop and signals
  // |background_io_completed_callback_|, in case the destructor is waiting.  In
  // that case, the destructor will call RunAsynchronousCallback() instead, and
  // cancel |message_loop_task_|.
  // |result| is the result of the Read/Write task.
  void OnBackgroundIOCompleted(int result);

 private:
  // Always called on the IO thread, either directly by a task on the
  // MessageLoop or by ~AsyncContext().
  void RunAsynchronousCallback();

  // The MessageLoopForIO that this AsyncContext is running on.
  MessageLoopForIO* const message_loop_;
  CompletionCallback* callback_;  // The user provided callback.

  // A callback wrapper around OnBackgroundIOCompleted().  Run by the WorkerPool
  // thread doing the background IO on our behalf.
  CompletionCallbackImpl<AsyncContext> background_io_completed_callback_;

  // This is used to synchronize between the AsyncContext destructor (which runs
  // on the IO thread and OnBackgroundIOCompleted() which runs on the WorkerPool
  // thread.
  base::WaitableEvent background_io_completed_;

  // These variables are only valid when background_io_completed is signaled.
  int result_;
  CancelableCallbackTask* message_loop_task_;

  bool is_closing_;

  DISALLOW_COPY_AND_ASSIGN(AsyncContext);
};

FileStream::AsyncContext::AsyncContext()
    : message_loop_(MessageLoopForIO::current()),
      callback_(NULL),
      background_io_completed_callback_(
          this, &AsyncContext::OnBackgroundIOCompleted),
      background_io_completed_(true, false),
      message_loop_task_(NULL),
      is_closing_(false) {}

FileStream::AsyncContext::~AsyncContext() {
  is_closing_ = true;
  if (callback_) {
    // If |callback_| is non-NULL, that implies either the worker thread is
    // still running the IO task, or the completion callback is queued up on the
    // MessageLoopForIO, but AsyncContext() got deleted before then.
    const bool need_to_wait = !background_io_completed_.IsSignaled();
    base::TimeTicks start = base::TimeTicks::Now();
    RunAsynchronousCallback();
    if (need_to_wait) {
      // We want to see if we block the message loop for too long.
      UMA_HISTOGRAM_TIMES("AsyncIO.FileStreamClose",
                          base::TimeTicks::Now() - start);
    }
  }
}

void FileStream::AsyncContext::InitiateAsyncRead(
    base::PlatformFile file, char* buf, int buf_len,
    CompletionCallback* callback) {
  DCHECK(!callback_);
  callback_ = callback;

  WorkerPool::PostTask(FROM_HERE,
                       new BackgroundReadTask(
                           file, buf, buf_len,
                           &background_io_completed_callback_),
                       true /* task_is_slow */);
}

void FileStream::AsyncContext::InitiateAsyncWrite(
    base::PlatformFile file, const char* buf, int buf_len,
    CompletionCallback* callback) {
  DCHECK(!callback_);
  callback_ = callback;

  WorkerPool::PostTask(FROM_HERE,
                       new BackgroundWriteTask(
                           file, buf, buf_len,
                           &background_io_completed_callback_),
                       true /* task_is_slow */);
}

void FileStream::AsyncContext::OnBackgroundIOCompleted(int result) {
  result_ = result;
  message_loop_task_ = new CancelableCallbackTask(
      NewCallback(this, &AsyncContext::RunAsynchronousCallback));
  message_loop_->PostTask(FROM_HERE, message_loop_task_);
  background_io_completed_.Signal();
}

void FileStream::AsyncContext::RunAsynchronousCallback() {
  // Wait() here ensures that all modifications from the WorkerPool thread are
  // now visible.
  background_io_completed_.Wait();

  // Either we're in the MessageLoop's task, in which case Cancel() doesn't do
  // anything, or we're in ~AsyncContext(), in which case this prevents the call
  // from happening again.  Must do it here after calling Wait().
  message_loop_task_->Cancel();
  message_loop_task_ = NULL;

  if (is_closing_) {
    callback_ = NULL;
    return;
  }

  DCHECK(callback_);
  CompletionCallback* temp = NULL;
  std::swap(temp, callback_);
  background_io_completed_.Reset();
  temp->Run(result_);
}

// FileStream ------------------------------------------------------------

FileStream::FileStream()
    : file_(base::kInvalidPlatformFileValue),
      open_flags_(0),
      auto_closed_(true) {
  DCHECK(!IsOpen());
}

FileStream::FileStream(base::PlatformFile file, int flags)
    : file_(file),
      open_flags_(flags),
      auto_closed_(false) {
  // If the file handle is opened with base::PLATFORM_FILE_ASYNC, we need to
  // make sure we will perform asynchronous File IO to it.
  if (flags & base::PLATFORM_FILE_ASYNC) {
    async_context_.reset(new AsyncContext());
  }
}

FileStream::~FileStream() {
  if (auto_closed_)
    Close();
}

void FileStream::Close() {
  // Abort any existing asynchronous operations.
  async_context_.reset();

  if (file_ != base::kInvalidPlatformFileValue) {
    if (close(file_) != 0) {
      NOTREACHED();
    }
    file_ = base::kInvalidPlatformFileValue;
  }
}

int FileStream::Open(const FilePath& path, int open_flags) {
  if (IsOpen()) {
    DLOG(FATAL) << "File is already open!";
    return ERR_UNEXPECTED;
  }

  open_flags_ = open_flags;
  file_ = base::CreatePlatformFile(path, open_flags_, NULL);
  if (file_ == base::kInvalidPlatformFileValue) {
    LOG(WARNING) << "Failed to open file: " << errno
          << " (" << path.ToWStringHack() << ")";
    return MapErrorCode(errno);
  }

  if (open_flags_ & base::PLATFORM_FILE_ASYNC) {
    async_context_.reset(new AsyncContext());
  }

  return OK;
}

bool FileStream::IsOpen() const {
  return file_ != base::kInvalidPlatformFileValue;
}

int64 FileStream::Seek(Whence whence, int64 offset) {
  if (!IsOpen())
    return ERR_UNEXPECTED;

  // If we're in async, make sure we don't have a request in flight.
  DCHECK(!async_context_.get() || !async_context_->callback());

  off_t res = lseek(file_, static_cast<off_t>(offset),
                    static_cast<int>(whence));
  if (res == static_cast<off_t>(-1))
    return MapErrorCode(errno);

  return res;
}

int64 FileStream::Available() {
  if (!IsOpen())
    return ERR_UNEXPECTED;

  int64 cur_pos = Seek(FROM_CURRENT, 0);
  if (cur_pos < 0)
    return cur_pos;

  struct stat info;
  if (fstat(file_, &info) != 0)
    return MapErrorCode(errno);

  int64 size = static_cast<int64>(info.st_size);
  DCHECK_GT(size, cur_pos);

  return size - cur_pos;
}

int FileStream::Read(
    char* buf, int buf_len, CompletionCallback* callback) {
  if (!IsOpen())
    return ERR_UNEXPECTED;

  // read(..., 0) will return 0, which indicates end-of-file.
  DCHECK(buf_len > 0);
  DCHECK(open_flags_ & base::PLATFORM_FILE_READ);

  if (async_context_.get()) {
    DCHECK(open_flags_ & base::PLATFORM_FILE_ASYNC);
    // If we're in async, make sure we don't have a request in flight.
    DCHECK(!async_context_->callback());
    async_context_->InitiateAsyncRead(file_, buf, buf_len, callback);
    return ERR_IO_PENDING;
  } else {
    return ReadFile(file_, buf, buf_len);
  }
}

int FileStream::ReadUntilComplete(char *buf, int buf_len) {
  int to_read = buf_len;
  int bytes_total = 0;

  do {
    int bytes_read = Read(buf, to_read, NULL);
    if (bytes_read <= 0) {
      if (bytes_total == 0)
        return bytes_read;

      return bytes_total;
    }

    bytes_total += bytes_read;
    buf += bytes_read;
    to_read -= bytes_read;
  } while (bytes_total < buf_len);

  return bytes_total;
}

int FileStream::Write(
    const char* buf, int buf_len, CompletionCallback* callback) {
  // write(..., 0) will return 0, which indicates end-of-file.
  DCHECK(buf_len > 0);

  if (!IsOpen())
    return ERR_UNEXPECTED;

  if (async_context_.get()) {
    DCHECK(open_flags_ & base::PLATFORM_FILE_ASYNC);
    // If we're in async, make sure we don't have a request in flight.
    DCHECK(!async_context_->callback());
    async_context_->InitiateAsyncWrite(file_, buf, buf_len, callback);
    return ERR_IO_PENDING;
  } else {
    return WriteFile(file_, buf, buf_len);
  }
}

int64 FileStream::Truncate(int64 bytes) {
  if (!IsOpen())
    return ERR_UNEXPECTED;

  // We better be open for reading.
  DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE);

  // Seek to the position to truncate from.
  int64 seek_position = Seek(FROM_BEGIN, bytes);
  if (seek_position != bytes)
    return ERR_UNEXPECTED;

  // And truncate the file.
  int result = ftruncate(file_, bytes);
  return result == 0 ? seek_position : MapErrorCode(errno);
}

}  // namespace net
<|endoftext|>


<commit_before>/*  This file is part of the KDE project
    Copyright (C) 2009 Colin Guthrie <cguthrie@mandriva.org>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) version 3, or any
    later version accepted by the membership of KDE e.V. (or its
    successor approved by the membership of KDE e.V.), Nokia Corporation
    (or its successors, if any) and the KDE Free Qt Foundation, which shall
    act as a proxy defined in Section 6 of version 3 of the license.

    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, see <http://www.gnu.org/licenses/>.

*/

#include <stdio.h>
#include <glib.h>
#include <QtCore/QtGlobal>
#include <QtCore/QEventLoop>
#include <QtCore/QDebug>

#ifdef HAVE_PULSEAUDIO
#include <pulse/pulseaudio.h>
#include <pulse/glib-mainloop.h>
#include <pulse/ext-device-manager.h>
#endif // HAVE_PULSEAUDIO

#include "pulsesupport_p.h"

QT_BEGIN_NAMESPACE

namespace Phonon
{

#ifdef HAVE_PULSEAUDIO
class PulseUserData
{
    public:
        inline
        PulseUserData(QEventLoop *eventLoop)
            : m_eventLoop(eventLoop)
        {
            Q_ASSERT(eventLoop);
        }

        inline void initialConnectionLoopExit()
        {
            m_eventLoop->exit(0);
            m_eventLoop = NULL;
        }
    private:
        QEventLoop *m_eventLoop;
};

/***
* Prints a conditional debug message based on the current debug level
* If obj is provided, classname and objectname will be printed as well
*
* see debugLevel()
*/

static int debugLevel() {
    return 2;
}

static void logMessage(const QString &message, int priority = 2, QObject *obj=0);
static void logMessage(const QString &message, int priority, QObject *obj)
{
    if (debugLevel() > 0) {
        QString output;
        if (obj) {
            // Strip away namespace from className
            QString className(obj->metaObject()->className());
            int nameLength = className.length() - className.lastIndexOf(':') - 1;
            className = className.right(nameLength);
            output.sprintf("%s %s (%s %p)", message.toLatin1().constData(),
                           obj->objectName().toLatin1().constData(),
                           className.toLatin1().constData(), obj);
        }
        else {
            output = message;
        }
        if (priority <= debugLevel()) {
            qDebug() << QString("PulseSupport(%1): %2").arg(priority).arg(output);
        }
    }
}

static PulseSupport* s_instance = NULL;
static bool s_pulseActive = false;

static pa_glib_mainloop *s_mainloop = NULL;
static pa_context *s_context = NULL;

static void ext_device_manager_read_cb(pa_context *c, const pa_ext_device_manager_info *info, int eol, void *) {
    Q_ASSERT(c);

    if (eol < 0) {
        logMessage(QString("Failed to initialize device manager extension: %1").arg(pa_strerror(pa_context_errno(c))));
        return;
    }

    if (!info)
        return;

    /* Do something with a widget when this part is written */
    logMessage(QString("Found: %1 '%2'").arg(info->name).arg(info->description));
}

static void ext_device_manager_subscribe_cb(pa_context *c, void *userdata) {
    Q_ASSERT(c);

    pa_operation *o;
    if (!(o = pa_ext_device_manager_read(c, ext_device_manager_read_cb, userdata))) {
        logMessage(QString("pa_ext_device_manager_read() failed"));
        return;
    }
    pa_operation_unref(o);
}

static void context_state_callback(pa_context *c, void *userdata)
{
    PulseUserData *u = reinterpret_cast<PulseUserData *>(userdata);
    switch (pa_context_get_state(c)) {
        case PA_CONTEXT_UNCONNECTED:
        case PA_CONTEXT_CONNECTING:
        case PA_CONTEXT_AUTHORIZING:
        case PA_CONTEXT_SETTING_NAME:
            break;

        case PA_CONTEXT_READY:
            u->initialConnectionLoopExit();

            pa_operation *o;

            if ((o = pa_ext_device_manager_read(c, ext_device_manager_read_cb, u))) {
                pa_operation_unref(o);

                pa_ext_device_manager_set_subscribe_cb(c, ext_device_manager_subscribe_cb, u);

                if ((o = pa_ext_device_manager_subscribe(c, 1, NULL, NULL)))
                    pa_operation_unref(o);

            } else
                logMessage(QString("Failed to initialize stream_restore extension: %1").arg(pa_strerror(pa_context_errno(c))));

            s_pulseActive = true;
            break;

        case PA_CONTEXT_FAILED:
            s_pulseActive = false;
            u->initialConnectionLoopExit();
            break;

        case PA_CONTEXT_TERMINATED:
        default:
            s_pulseActive = false;
            /// @todo Deal with reconnection...
            break;
    }
}

#endif // HAVE_PULSEAUDIO

PulseSupport* PulseSupport::getInstance()
{
    if (NULL == s_instance) {
        s_instance = new PulseSupport();
    }
    return s_instance;
}

void PulseSupport::shutdown()
{
    if (NULL != s_instance) {
        delete s_instance;
        s_instance = NULL;
    }
}

PulseSupport::PulseSupport()
{
#ifdef HAVE_PULSEAUDIO
    // To allow for easy debugging, give an easy way to disable this pulseaudio check
    QString pulseenv = qgetenv("PHONON_DISABLE_PULSEAUDIO");
    if (pulseenv.toInt())
        return;

    s_mainloop = pa_glib_mainloop_new(NULL);
    Q_ASSERT(s_mainloop);
    pa_mainloop_api *api = pa_glib_mainloop_get_api(s_mainloop);

    // We create a simple event loop to allow the glib loop
    // to iterate until we've connected or not to the server.
    QEventLoop loop;
    PulseUserData* userData = new PulseUserData(&loop);

    // XXX I don't want to show up in the client list. All I want to know is the list of sources
    // and sinks...
    s_context = pa_context_new(api, "libphonon");
    // (cg) Convert to PA_CONTEXT_NOFLAGS when PulseAudio 0.9.19 is required
    if (pa_context_connect(s_context, NULL, static_cast<pa_context_flags_t>(0), 0) >= 0) {
        pa_context_set_state_callback(s_context, &context_state_callback, userData);
        // Now we block until we connect or otherwise...
        loop.exec();
    }
#endif
}

PulseSupport::~PulseSupport()
{
#ifdef HAVE_PULSEAUDIO
    if (s_context) {
        pa_context_disconnect(s_context);
        s_context = NULL;
    }

    if (s_mainloop) {
        pa_glib_mainloop_free(s_mainloop);
        s_mainloop = NULL;
    }
#endif
}

bool PulseSupport::isActive()
{
#ifdef HAVE_PULSEAUDIO
    return s_pulseActive;
#else
    return false;
#endif
}

} // namespace Phonon

QT_END_NAMESPACE

// vim: sw=4 ts=4
<commit_msg>pulseaudio: Process the device list from pulseaudio and maintain an internal cache.<commit_after>/*  This file is part of the KDE project
    Copyright (C) 2009 Colin Guthrie <cguthrie@mandriva.org>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) version 3, or any
    later version accepted by the membership of KDE e.V. (or its
    successor approved by the membership of KDE e.V.), Nokia Corporation
    (or its successors, if any) and the KDE Free Qt Foundation, which shall
    act as a proxy defined in Section 6 of version 3 of the license.

    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, see <http://www.gnu.org/licenses/>.

*/

#include <QtCore/QtGlobal>
#include <QtCore/QEventLoop>
#include <QtCore/QDebug>

#ifdef HAVE_PULSEAUDIO
#include <glib.h>
#include <pulse/pulseaudio.h>
#include <pulse/glib-mainloop.h>
#include <pulse/ext-device-manager.h>
#endif // HAVE_PULSEAUDIO

#include "pulsesupport_p.h"
#include "phononnamespace.h"

QT_BEGIN_NAMESPACE

namespace Phonon
{

#ifdef HAVE_PULSEAUDIO
/***
* Prints a conditional debug message based on the current debug level
* If obj is provided, classname and objectname will be printed as well
*
* see debugLevel()
*/

static int debugLevel() {
    return 2;
}

static void logMessage(const QString &message, int priority = 2, QObject *obj=0);
static void logMessage(const QString &message, int priority, QObject *obj)
{
    if (debugLevel() > 0) {
        QString output;
        if (obj) {
            // Strip away namespace from className
            QString className(obj->metaObject()->className());
            int nameLength = className.length() - className.lastIndexOf(':') - 1;
            className = className.right(nameLength);
            output.sprintf("%s %s (%s %p)", message.toLatin1().constData(),
                           obj->objectName().toLatin1().constData(),
                           className.toLatin1().constData(), obj);
        }
        else {
            output = message;
        }
        if (priority <= debugLevel()) {
            qDebug() << QString("PulseSupport(%1): %2").arg(priority).arg(output);
        }
    }
}

class AudioDevice
{
    public:
        inline
        AudioDevice(QString name, unsigned int priority, QString desc, QString icon)
        : pulseName(name)
        , pulsePriority(priority)
        , description(desc)
        , icon(icon)
        , isAdvanced(false)
        {
            /*logMessage(QString("Adding '%1' (priority: %2)").arg(desc).arg(priority));*/
        }

        QString pulseName;
        unsigned int pulsePriority;
        QString description;
        QString icon;
        bool isAdvanced;
};
bool operator<(const AudioDevice &a, const AudioDevice &b)
{
    return a.pulsePriority < b.pulsePriority;
}

class PulseUserData
{
    public:
        inline
        PulseUserData()
        {
        }

        QMap<Phonon::Category, QList<AudioDevice> > outputDevices;
        QMap<Phonon::Category, QList<AudioDevice> > captureDevices;
};

static QMap<QString, Phonon::Category> s_role_category_map;

static PulseSupport* s_instance = NULL;
static bool s_pulseActive = false;

static pa_glib_mainloop *s_mainloop = NULL;
static pa_context *s_context = NULL;
static QEventLoop *s_connection_eventloop = NULL;

QMap<Phonon::Category, QList<AudioDevice> > s_output_devices;
QMap<Phonon::Category, QList<AudioDevice> > s_capture_devices;

static void ext_device_manager_subscribe_cb(pa_context *, void *);
static void ext_device_manager_read_cb(pa_context *c, const pa_ext_device_manager_info *info, int eol, void *userdata) {
    Q_ASSERT(c);
    Q_ASSERT(userdata);

    // If this is our first iteration, set things up properly
    if (s_connection_eventloop) {
        s_connection_eventloop->exit(0);
        s_connection_eventloop = NULL;
        s_pulseActive = true;

        pa_operation *o;
        pa_ext_device_manager_set_subscribe_cb(c, ext_device_manager_subscribe_cb, NULL);
        if ((o = pa_ext_device_manager_subscribe(c, 1, NULL, NULL)))
            pa_operation_unref(o);
    }

    if (eol < 0) {
        logMessage(QString("Failed to initialize device manager extension: %1").arg(pa_strerror(pa_context_errno(c))));
        s_pulseActive = false;
        return;
    }

    PulseUserData *u = reinterpret_cast<PulseUserData*>(userdata);
    if (eol) {
        // We're done reading the data, so order it by priority and copy it into the
        // static variables where it can then be accessed by those classes that need it.

        QMap<Phonon::Category, QList<AudioDevice> >::iterator it;
        for (it = u->outputDevices.begin(); it != u->outputDevices.end(); ++it) {
            QList<AudioDevice> &list = it.value();
            qSort(list);
        }
        s_output_devices = u->outputDevices;
        for (it = u->captureDevices.begin(); it != u->captureDevices.end(); ++it) {
            QList<AudioDevice> &list = it.value();
            qSort(list);
        }
        s_capture_devices = u->captureDevices;

        // Also free the user data as we will not be called again.
        delete u;

        // Some debug
        logMessage(QString("Output Device Priority List:"));
        for (int i = Phonon::NoCategory; i <= Phonon::LastCategory; ++i) {
            Phonon::Category cat = static_cast<Phonon::Category>(i);
            if (s_output_devices.contains(cat)) {
                logMessage(QString("  Phonon Category %1").arg(cat));
                QList<AudioDevice>::iterator it;
                int j = 0;
                for (it = s_output_devices[cat].begin(); it != s_output_devices[cat].end(); ++it) {
                    logMessage(QString("    %1. %2").arg(++j).arg((*it).description));
                }
            }
        }
        logMessage(QString("Capture Device Priority List:"));
        for (int i = Phonon::NoCategory; i <= Phonon::LastCategory; ++i) {
            Phonon::Category cat = static_cast<Phonon::Category>(i);
            if (s_capture_devices.contains(cat)) {
                logMessage(QString("  Phonon Category %1").arg(cat));
                QList<AudioDevice>::iterator it;
                int j = 0;
                for (it = s_capture_devices[cat].begin(); it != s_capture_devices[cat].end(); ++it) {
                    logMessage(QString("    %1. %2").arg(++j).arg((*it).description));
                }
            }
        }
    }

    if (!info)
        return;

    Q_ASSERT(info->name);
    Q_ASSERT(info->description);
    Q_ASSERT(info->icon);

    // For each role in the priority, map it to a phonon category and store the order.
    for (uint32_t i = 0; i < info->n_role_priorities; ++i) {
        pa_ext_device_manager_role_priority_info* role_prio = &info->role_priorities[i];
        Q_ASSERT(role_prio->role);

        if (s_role_category_map.contains(role_prio->role)) {
            Phonon::Category cat = s_role_category_map[role_prio->role];
            QList<AudioDevice> *list;
            QString name(info->name);

            if (name.startsWith("sink:")) {
                if (!u->outputDevices.contains(cat))
                    u->outputDevices.insert(cat, QList<AudioDevice>());
                list = &u->outputDevices[cat];
            } else if (name.startsWith("source:")) {
                if (!u->captureDevices.contains(cat))
                    u->captureDevices.insert(cat, QList<AudioDevice>());
                list = &u->captureDevices[cat];
            } else {
                continue;
            }

            list->append(AudioDevice(info->name, role_prio->priority, info->description, info->icon));
        }
    }
}

static void ext_device_manager_subscribe_cb(pa_context *c, void *) {
    Q_ASSERT(c);

    pa_operation *o;
    PulseUserData *u = new PulseUserData; /** @todo Make some object to receive the info... */
    if (!(o = pa_ext_device_manager_read(c, ext_device_manager_read_cb, u))) {
        // We need to deal with failure on first iteration
        if (s_connection_eventloop) {
            s_connection_eventloop->exit(0);
            s_connection_eventloop = NULL;
        }
        logMessage(QString("pa_ext_device_manager_read() failed"));
        return;
    }
    pa_operation_unref(o);
}

static void context_state_callback(pa_context *c, void *)
{
    Q_ASSERT(c);

    switch (pa_context_get_state(c)) {
        case PA_CONTEXT_UNCONNECTED:
        case PA_CONTEXT_CONNECTING:
        case PA_CONTEXT_AUTHORIZING:
        case PA_CONTEXT_SETTING_NAME:
            break;

        case PA_CONTEXT_READY:
            // Attempt to load things up
            ext_device_manager_subscribe_cb(c, NULL);
            break;

        case PA_CONTEXT_FAILED:
            s_pulseActive = false;
            if (s_connection_eventloop) {
                s_connection_eventloop->exit(0);
                s_connection_eventloop = NULL;
            }
            break;

        case PA_CONTEXT_TERMINATED:
        default:
            s_pulseActive = false;
            /// @todo Deal with reconnection...
            break;
    }
}
#endif // HAVE_PULSEAUDIO

PulseSupport* PulseSupport::getInstance()
{
    if (NULL == s_instance) {
        s_instance = new PulseSupport();
    }
    return s_instance;
}

void PulseSupport::shutdown()
{
    if (NULL != s_instance) {
        delete s_instance;
        s_instance = NULL;
    }
}

PulseSupport::PulseSupport()
{
    s_role_category_map["none"] = Phonon::NoCategory;
    s_role_category_map["video"] = Phonon::VideoCategory;
    s_role_category_map["music"] = Phonon::MusicCategory;
    s_role_category_map["game"] = Phonon::GameCategory;
    s_role_category_map["event"] = Phonon::NotificationCategory;
    s_role_category_map["phone"] = Phonon::CommunicationCategory;
    //s_role_category_map["animation"] = Phonon::NoCategory; // No Mapping
    //s_role_category_map["production"] = Phonon::NoCategory; // No Mapping
    s_role_category_map["a11y"] = Phonon::AccessibilityCategory;

#ifdef HAVE_PULSEAUDIO
    // To allow for easy debugging, give an easy way to disable this pulseaudio check
    QString pulseenv = qgetenv("PHONON_DISABLE_PULSEAUDIO");
    if (pulseenv.toInt())
        return;

    s_mainloop = pa_glib_mainloop_new(NULL);
    Q_ASSERT(s_mainloop);
    pa_mainloop_api *api = pa_glib_mainloop_get_api(s_mainloop);

    // We create a simple event loop to allow the glib loop
    // to iterate until we've connected or not to the server.
    s_connection_eventloop = new QEventLoop;

    // XXX I don't want to show up in the client list. All I want to know is the list of sources
    // and sinks...
    s_context = pa_context_new(api, "libphonon");
    // (cg) Convert to PA_CONTEXT_NOFLAGS when PulseAudio 0.9.19 is required
    if (pa_context_connect(s_context, NULL, static_cast<pa_context_flags_t>(0), 0) >= 0) {
        pa_context_set_state_callback(s_context, &context_state_callback, s_connection_eventloop);
        // Now we block until we connect or otherwise...
        s_connection_eventloop->exec();
    }
#endif
}

PulseSupport::~PulseSupport()
{
#ifdef HAVE_PULSEAUDIO
    if (s_context) {
        pa_context_disconnect(s_context);
        s_context = NULL;
    }

    if (s_mainloop) {
        pa_glib_mainloop_free(s_mainloop);
        s_mainloop = NULL;
    }

    if (s_connection_eventloop) {
        delete s_connection_eventloop;
        s_connection_eventloop = NULL;
    }
#endif
}

bool PulseSupport::isActive()
{
#ifdef HAVE_PULSEAUDIO
    return s_pulseActive;
#else
    return false;
#endif
}

} // namespace Phonon

QT_END_NAMESPACE

// vim: sw=4 ts=4
<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Insight Segmentation & Registration Toolkit
  Module:    itkImportContainerTest.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) Insight Software Consortium. All rights reserved.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
#if defined(_MSC_VER)
#pragma warning ( disable : 4786 )
#endif

#include <iostream>
#include "itkImportImageContainer.h"
#include "itkNumericTraits.h"
#include "itkOutputWindow.h"
#include "itkTextOutput.h"

int itkImportContainerTest(int , char * [] )
{
  typedef float PixelType;
  typedef itk::ImportImageContainer<unsigned long, PixelType> ContainerType;

  itk::OutputWindow::SetInstance(itk::TextOutput::New());

// First test with ContainerManagesMemory false
  PixelType *ptr1;
  {
  // Test 1: Create an empty container and print it
  ContainerType::Pointer container1 = ContainerType::New();
  container1->Print(std::cout);
  std::cout << "After New(), size is "
            << container1->Size()
            << ", capacity is "
            <<  container1->Capacity()
            << " and import pointer is "
            << container1->GetImportPointer()
            << std::endl;

  // Test 2: Reserve memory
  container1->Reserve(1000);
  std::cout << "After container1->Reserve(1000), size is "
            << container1->Size()
            << ", capacity is "
            <<  container1->Capacity()
            << " and import pointer is "
            << container1->GetImportPointer()
            << std::endl;

  // Take control of the pointer
  container1->ContainerManageMemoryOff();
  ptr1 = container1->GetImportPointer();

  // Test 3: Reserve a smaller amount of memory
  container1->Reserve(100);
  std::cout << "After container1->Reserve(100), size is "
            << container1->Size()
            << ", capacity is "
            <<  container1->Capacity()
            << " and import pointer is "
            << container1->GetImportPointer()
            << std::endl;

  // Test 4: Squeeze the container
  container1->Squeeze();
  std::cout << "After container1->Squeeze() size is "
            << container1->Size()
            << ", capacity is "
            <<  container1->Capacity()
            << " and import pointer is "
            << container1->GetImportPointer()
            << std::endl;

  // Test 5: Initialize the container
  container1->Initialize();
  std::cout << "After container1->Initialize() size is "
            << container1->Size()
            << ", capacity is "
            <<  container1->Capacity()
            << " and import pointer is "
            << container1->GetImportPointer()
            << std::endl;
  }

// now repeat the tests with a user provided pointer
  PixelType *myPtr = new float[2000];
  {
  // Test 1: Create an empty container and print it
  ContainerType::Pointer container1 = ContainerType::New();
  container1->Print(std::cout);
  std::cout << "After New(), size is "
            << container1->Size()
            << ", capacity is "
            <<  container1->Capacity()
            << " and import pointer is "
            << container1->GetImportPointer()
            << std::endl;

  container1->SetImportPointer(myPtr, 2000);
  std::cout << "After New(), size is "
            << container1->Size()
            << ", capacity is "
            <<  container1->Capacity()
            << " and import pointer is "
            << container1->GetImportPointer()
            << std::endl;

  *(myPtr + 500) = 500.0;

  // Test 2: Reserve less memory than capacity
  container1->Reserve(1000);
  std::cout << "After container1->Reserve(1000), size is "
            << container1->Size()
            << ", capacity is "
            <<  container1->Capacity()
            << " and import pointer is "
            << container1->GetImportPointer()
            << std::endl;

  if (*(myPtr + 500) != 500.0)
    {
    std::cout << "Test failed: After container1->Reserve(1000), container1[500] does != 500." << std::endl;
    return EXIT_FAILURE;
    }

  // Test 3: Reserve more memory than capacity
  container1->Reserve(10000);
  std::cout << "After container1->Reserve(100), size is "
            << container1->Size()
            << ", capacity is "
            <<  container1->Capacity()
            << " and import pointer is "
            << container1->GetImportPointer()
            << std::endl;
  if (*(myPtr + 500) != 500.0)
    {
    std::cout << "Test failed: After container1->Reserve(10000), container1[500] does != 500." << std::endl;
    return EXIT_FAILURE;
    }

  // Test 4: Squeeze the container
  container1->Squeeze();
  std::cout << "After container1->Squeeze() size is "
            << container1->Size()
            << ", capacity is "
            <<  container1->Capacity()
            << " and import pointer is "
            << container1->GetImportPointer()
            << std::endl;

  if (*(myPtr + 500) != 500.0)
    {
    std::cout << "Test failed: After container1->Squeeze(), container1[500] does != 500." << std::endl;
    return EXIT_FAILURE;
    }

  // Test 5: Initialize the container
  container1->Initialize();
  std::cout << "After container1->Initialize() size is "
            << container1->Size()
            << ", capacity is "
            <<  container1->Capacity()
            << " and import pointer is "
            << container1->GetImportPointer()
            << std::endl;
  }

  // Now repeat tests with ContainerManagesMemory true
  {
  // Test 1: Create an empty container and print it
  ContainerType::Pointer container1 = ContainerType::New();
  container1->Print(std::cout);
  std::cout << "After New(), size is "
            << container1->Size()
            << ", capacity is "
            <<  container1->Capacity()
            << " and import pointer is "
            << container1->GetImportPointer()
            << std::endl;

  // Test 2: Reserve memory
  container1->Reserve(1000);
  std::cout << "After container1->Reserve(1000), size is "
            << container1->Size()
            << ", capacity is "
            <<  container1->Capacity()
            << " and import pointer is "
            << container1->GetImportPointer()
            << std::endl;

  // Test 3: Reserve a smaller amount of memory
  container1->Reserve(100);
  std::cout << "After container1->Reserve(100), size is "
            << container1->Size()
            << ", capacity is "
            <<  container1->Capacity()
            << " and import pointer is "
            << container1->GetImportPointer()
            << std::endl;

  // Test 4: Squeeze the container
  container1->Squeeze();
  std::cout << "After container1->Squeeze() size is "
            << container1->Size()
            << ", capacity is "
            <<  container1->Capacity()
            << " and import pointer is "
            << container1->GetImportPointer()
            << std::endl;

  // Test 5: Initialize the container
  container1->Initialize();
  std::cout << "After container1->Initialize() size is "
            << container1->Size()
            << ", capacity is "
            <<  container1->Capacity()
            << " and import pointer is "
            << container1->GetImportPointer()
            << std::endl;
  }

  // SGI's always say they can get you the memory you want.
#if !defined(__sgi)
  // Check the exception on the memory allocation
  bool caughtException = false;
  try
    {
    ContainerType::Pointer container1 = ContainerType::New();
    container1->Reserve( itk::NumericTraits<unsigned long>::max()/sizeof(PixelType));
    }
  catch (itk::ExceptionObject& err)
    {
    std::cout << "Caught expected exception: " << err << std::endl;
    caughtException = true;
    }
#endif

  // We must delete the memory we said we would manage
  delete [] ptr1;
  delete [] myPtr;

  // SGI's always say they can get you the memory you want.
#if !defined(__sgi)
  if (!caughtException)
    {
    std::cout << "Failed to catch expected exception" << std::endl;
    return EXIT_FAILURE;
    }
#endif
  return EXIT_SUCCESS;
}
<commit_msg>COMP: for valgrinds sake, avoid the oversized memory allocation.<commit_after>/*=========================================================================

  Program:   Insight Segmentation & Registration Toolkit
  Module:    itkImportContainerTest.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) Insight Software Consortium. All rights reserved.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
#if defined(_MSC_VER)
#pragma warning ( disable : 4786 )
#endif

#include <iostream>
#include "itkImportImageContainer.h"
#include "itkNumericTraits.h"
#include "itkOutputWindow.h"
#include "itkTextOutput.h"

int itkImportContainerTest(int , char * [] )
{
  typedef float PixelType;
  typedef itk::ImportImageContainer<unsigned long, PixelType> ContainerType;

  itk::OutputWindow::SetInstance(itk::TextOutput::New());

// First test with ContainerManagesMemory false
  PixelType *ptr1;
  {
  // Test 1: Create an empty container and print it
  ContainerType::Pointer container1 = ContainerType::New();
  container1->Print(std::cout);
  std::cout << "After New(), size is "
            << container1->Size()
            << ", capacity is "
            <<  container1->Capacity()
            << " and import pointer is "
            << container1->GetImportPointer()
            << std::endl;

  // Test 2: Reserve memory
  container1->Reserve(1000);
  std::cout << "After container1->Reserve(1000), size is "
            << container1->Size()
            << ", capacity is "
            <<  container1->Capacity()
            << " and import pointer is "
            << container1->GetImportPointer()
            << std::endl;

  // Take control of the pointer
  container1->ContainerManageMemoryOff();
  ptr1 = container1->GetImportPointer();

  // Test 3: Reserve a smaller amount of memory
  container1->Reserve(100);
  std::cout << "After container1->Reserve(100), size is "
            << container1->Size()
            << ", capacity is "
            <<  container1->Capacity()
            << " and import pointer is "
            << container1->GetImportPointer()
            << std::endl;

  // Test 4: Squeeze the container
  container1->Squeeze();
  std::cout << "After container1->Squeeze() size is "
            << container1->Size()
            << ", capacity is "
            <<  container1->Capacity()
            << " and import pointer is "
            << container1->GetImportPointer()
            << std::endl;

  // Test 5: Initialize the container
  container1->Initialize();
  std::cout << "After container1->Initialize() size is "
            << container1->Size()
            << ", capacity is "
            <<  container1->Capacity()
            << " and import pointer is "
            << container1->GetImportPointer()
            << std::endl;
  }

// now repeat the tests with a user provided pointer
  PixelType *myPtr = new float[2000];
  {
  // Test 1: Create an empty container and print it
  ContainerType::Pointer container1 = ContainerType::New();
  container1->Print(std::cout);
  std::cout << "After New(), size is "
            << container1->Size()
            << ", capacity is "
            <<  container1->Capacity()
            << " and import pointer is "
            << container1->GetImportPointer()
            << std::endl;

  container1->SetImportPointer(myPtr, 2000);
  std::cout << "After New(), size is "
            << container1->Size()
            << ", capacity is "
            <<  container1->Capacity()
            << " and import pointer is "
            << container1->GetImportPointer()
            << std::endl;

  *(myPtr + 500) = 500.0;

  // Test 2: Reserve less memory than capacity
  container1->Reserve(1000);
  std::cout << "After container1->Reserve(1000), size is "
            << container1->Size()
            << ", capacity is "
            <<  container1->Capacity()
            << " and import pointer is "
            << container1->GetImportPointer()
            << std::endl;

  if (*(myPtr + 500) != 500.0)
    {
    std::cout << "Test failed: After container1->Reserve(1000), container1[500] does != 500." << std::endl;
    return EXIT_FAILURE;
    }

  // Test 3: Reserve more memory than capacity
  container1->Reserve(10000);
  std::cout << "After container1->Reserve(100), size is "
            << container1->Size()
            << ", capacity is "
            <<  container1->Capacity()
            << " and import pointer is "
            << container1->GetImportPointer()
            << std::endl;
  if (*(myPtr + 500) != 500.0)
    {
    std::cout << "Test failed: After container1->Reserve(10000), container1[500] does != 500." << std::endl;
    return EXIT_FAILURE;
    }

  // Test 4: Squeeze the container
  container1->Squeeze();
  std::cout << "After container1->Squeeze() size is "
            << container1->Size()
            << ", capacity is "
            <<  container1->Capacity()
            << " and import pointer is "
            << container1->GetImportPointer()
            << std::endl;

  if (*(myPtr + 500) != 500.0)
    {
    std::cout << "Test failed: After container1->Squeeze(), container1[500] does != 500." << std::endl;
    return EXIT_FAILURE;
    }

  // Test 5: Initialize the container
  container1->Initialize();
  std::cout << "After container1->Initialize() size is "
            << container1->Size()
            << ", capacity is "
            <<  container1->Capacity()
            << " and import pointer is "
            << container1->GetImportPointer()
            << std::endl;
  }

  // Now repeat tests with ContainerManagesMemory true
  {
  // Test 1: Create an empty container and print it
  ContainerType::Pointer container1 = ContainerType::New();
  container1->Print(std::cout);
  std::cout << "After New(), size is "
            << container1->Size()
            << ", capacity is "
            <<  container1->Capacity()
            << " and import pointer is "
            << container1->GetImportPointer()
            << std::endl;

  // Test 2: Reserve memory
  container1->Reserve(1000);
  std::cout << "After container1->Reserve(1000), size is "
            << container1->Size()
            << ", capacity is "
            <<  container1->Capacity()
            << " and import pointer is "
            << container1->GetImportPointer()
            << std::endl;

  // Test 3: Reserve a smaller amount of memory
  container1->Reserve(100);
  std::cout << "After container1->Reserve(100), size is "
            << container1->Size()
            << ", capacity is "
            <<  container1->Capacity()
            << " and import pointer is "
            << container1->GetImportPointer()
            << std::endl;

  // Test 4: Squeeze the container
  container1->Squeeze();
  std::cout << "After container1->Squeeze() size is "
            << container1->Size()
            << ", capacity is "
            <<  container1->Capacity()
            << " and import pointer is "
            << container1->GetImportPointer()
            << std::endl;

  // Test 5: Initialize the container
  container1->Initialize();
  std::cout << "After container1->Initialize() size is "
            << container1->Size()
            << ", capacity is "
            <<  container1->Capacity()
            << " and import pointer is "
            << container1->GetImportPointer()
            << std::endl;
  }

  // valgrind has problems with exceptions after a failed memory
  // allocation. Since valgrind is normally built with debug, a check
  // for NDEBUG will eliminate this code. Unfortunately, coverage is
  // also built debug, so the coverage report will show that the
  // exception after a refused allocation is not exercised.
  // SGI's always say they can get you the memory you want.
#if (!defined(__sgi) && defined(NDEBUG))
  // Check the exception on the memory allocation
  bool caughtException = false;
  try
    {
    ContainerType::Pointer container1 = ContainerType::New();
    container1->Reserve( itk::NumericTraits<unsigned long>::max()/sizeof(PixelType));
    }
  catch (itk::ExceptionObject& err)
    {
    std::cout << "Caught expected exception: " << err << std::endl;
    caughtException = true;
    }
#endif

  // We must delete the memory we said we would manage
  delete [] ptr1;
  delete [] myPtr;

  // SGI's always say they can get you the memory you want.
#if (!defined(__sgi) && defined(NDEBUG))
  if (!caughtException)
    {
    std::cout << "Failed to catch expected exception" << std::endl;
    return EXIT_FAILURE;
    }
#endif
  return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>
#include "Globals.h"

#include "SpawnPrepare.h"
#include "World.h"

class cSpawnPrepareCallback :
	public cChunkCoordCallback
{
public:
	cSpawnPrepareCallback(cSpawnPrepare & a_SpawnPrepare) :
		m_SpawnPrepare(a_SpawnPrepare)
	{
	}
protected:

	cSpawnPrepare & m_SpawnPrepare;

	virtual void Call(int a_ChunkX, int a_ChunkZ, bool a_IsSuccess) override
	{
		m_SpawnPrepare.PreparedChunkCallback(a_ChunkX, a_ChunkZ);
	}
};

cSpawnPrepare::cSpawnPrepare(cWorld & a_World, int a_SpawnChunkX, int a_SpawnChunkZ, int a_PrepareDistance, int a_FirstIdx):
	m_World(a_World),
	m_SpawnChunkX(a_SpawnChunkX),
	m_SpawnChunkZ(a_SpawnChunkZ),
	m_PrepareDistance(a_PrepareDistance),
	m_NextIdx(a_FirstIdx),
	m_MaxIdx(a_PrepareDistance * a_PrepareDistance),
	m_NumPrepared(0),
	m_LastReportTime(std::chrono::steady_clock::now()),
	m_LastReportChunkCount(0)
{
}

void cSpawnPrepare::PrepareChunks(cWorld & a_World, int a_SpawnChunkX, int a_SpawnChunkZ, int a_PrepareDistance)
{

	// Queue the initial chunks:
	int MaxIdx = a_PrepareDistance * a_PrepareDistance;
	int maxQueue = std::min(MaxIdx - 1, 100);  // Number of chunks to queue at once
	cSpawnPrepare prep(a_World, a_SpawnChunkX, a_SpawnChunkZ, a_PrepareDistance, maxQueue);
	for (int i = 0; i < maxQueue; i++)
	{
		int chunkX, chunkZ;
		prep.DecodeChunkCoords(i, chunkX, chunkZ);
		a_World.PrepareChunk(chunkX, chunkZ, cpp14::make_unique<cSpawnPrepareCallback>(prep));
	}  // for i

	// Wait for the lighting thread to prepare everything. Event is set in the Call() callback:
	prep.m_EvtFinished.Wait();
}

void cSpawnPrepare::DecodeChunkCoords(int a_Idx, int & a_ChunkX, int & a_ChunkZ)
{
	// A zigzag pattern from the top to bottom, each row alternating between forward-x and backward-x:
	int z = a_Idx / m_PrepareDistance;
	int x = a_Idx % m_PrepareDistance;
	if ((z & 1) == 0)
	{
		// Reverse every second row:
		x = m_PrepareDistance - 1 - x;
	}
	a_ChunkZ = m_SpawnChunkZ + z - m_PrepareDistance / 2;
	a_ChunkX = m_SpawnChunkX + x - m_PrepareDistance / 2;
}

void cSpawnPrepare::PreparedChunkCallback(int a_ChunkX, int a_ChunkZ)
{
	// Check if this was the last chunk:
	m_NumPrepared += 1;
	if (m_NumPrepared >= m_MaxIdx)
	{
		m_EvtFinished.Set();
		// Must return here, because "this" may have gotten deleted by the previous line
		return;
	}

	// Queue another chunk, if appropriate:
	if (m_NextIdx < m_MaxIdx)
	{
		int chunkX, chunkZ;
		DecodeChunkCoords(m_NextIdx, chunkX, chunkZ);
		m_World.GetLightingThread().QueueChunk(chunkX, chunkZ, cpp14::make_unique<cSpawnPrepareCallback>(*this));
		m_NextIdx += 1;
	}

	// Report progress every 1 second:
	auto Now = std::chrono::steady_clock::now();
	if (Now - m_LastReportTime > std::chrono::seconds(1))
	{
		float PercentDone = static_cast<float>(m_NumPrepared * 100) / m_MaxIdx;
		float ChunkSpeed = static_cast<float>((m_NumPrepared - m_LastReportChunkCount) * 1000) / std::chrono::duration_cast<std::chrono::milliseconds>(Now - m_LastReportTime).count();
		LOG("Preparing spawn (%s): %.02f%% (%d/%d; %.02f chunks / sec)",
			m_World.GetName().c_str(), PercentDone, m_NumPrepared, m_MaxIdx, ChunkSpeed
		);
		m_LastReportTime = Now;
		m_LastReportChunkCount = m_NumPrepared;
	}
}

<commit_msg>Fix deadlock, resolves #2521<commit_after>
#include "Globals.h"

#include "SpawnPrepare.h"
#include "World.h"

class cSpawnPrepareCallback :
	public cChunkCoordCallback
{
public:
	cSpawnPrepareCallback(cSpawnPrepare & a_SpawnPrepare) :
		m_SpawnPrepare(a_SpawnPrepare)
	{
	}
protected:

	cSpawnPrepare & m_SpawnPrepare;

	virtual void Call(int a_ChunkX, int a_ChunkZ, bool a_IsSuccess) override
	{
		m_SpawnPrepare.PreparedChunkCallback(a_ChunkX, a_ChunkZ);
	}
};

cSpawnPrepare::cSpawnPrepare(cWorld & a_World, int a_SpawnChunkX, int a_SpawnChunkZ, int a_PrepareDistance, int a_FirstIdx):
	m_World(a_World),
	m_SpawnChunkX(a_SpawnChunkX),
	m_SpawnChunkZ(a_SpawnChunkZ),
	m_PrepareDistance(a_PrepareDistance),
	m_NextIdx(a_FirstIdx),
	m_MaxIdx(a_PrepareDistance * a_PrepareDistance),
	m_NumPrepared(0),
	m_LastReportTime(std::chrono::steady_clock::now()),
	m_LastReportChunkCount(0)
{
}

void cSpawnPrepare::PrepareChunks(cWorld & a_World, int a_SpawnChunkX, int a_SpawnChunkZ, int a_PrepareDistance)
{

	// Queue the initial chunks:
	int MaxIdx = a_PrepareDistance * a_PrepareDistance;
	int maxQueue = std::min(MaxIdx - 1, 100);  // Number of chunks to queue at once
	cSpawnPrepare prep(a_World, a_SpawnChunkX, a_SpawnChunkZ, a_PrepareDistance, maxQueue);
	for (int i = 0; i < maxQueue; i++)
	{
		int chunkX, chunkZ;
		prep.DecodeChunkCoords(i, chunkX, chunkZ);
		a_World.PrepareChunk(chunkX, chunkZ, cpp14::make_unique<cSpawnPrepareCallback>(prep));
	}  // for i

	// Wait for the lighting thread to prepare everything. Event is set in the Call() callback:
	if (MaxIdx > 0)
	{
		prep.m_EvtFinished.Wait();
	}
}

void cSpawnPrepare::DecodeChunkCoords(int a_Idx, int & a_ChunkX, int & a_ChunkZ)
{
	// A zigzag pattern from the top to bottom, each row alternating between forward-x and backward-x:
	int z = a_Idx / m_PrepareDistance;
	int x = a_Idx % m_PrepareDistance;
	if ((z & 1) == 0)
	{
		// Reverse every second row:
		x = m_PrepareDistance - 1 - x;
	}
	a_ChunkZ = m_SpawnChunkZ + z - m_PrepareDistance / 2;
	a_ChunkX = m_SpawnChunkX + x - m_PrepareDistance / 2;
}

void cSpawnPrepare::PreparedChunkCallback(int a_ChunkX, int a_ChunkZ)
{
	// Check if this was the last chunk:
	m_NumPrepared += 1;
	if (m_NumPrepared >= m_MaxIdx)
	{
		m_EvtFinished.Set();
		// Must return here, because "this" may have gotten deleted by the previous line
		return;
	}

	// Queue another chunk, if appropriate:
	if (m_NextIdx < m_MaxIdx)
	{
		int chunkX, chunkZ;
		DecodeChunkCoords(m_NextIdx, chunkX, chunkZ);
		m_World.GetLightingThread().QueueChunk(chunkX, chunkZ, cpp14::make_unique<cSpawnPrepareCallback>(*this));
		m_NextIdx += 1;
	}

	// Report progress every 1 second:
	auto Now = std::chrono::steady_clock::now();
	if (Now - m_LastReportTime > std::chrono::seconds(1))
	{
		float PercentDone = static_cast<float>(m_NumPrepared * 100) / m_MaxIdx;
		float ChunkSpeed = static_cast<float>((m_NumPrepared - m_LastReportChunkCount) * 1000) / std::chrono::duration_cast<std::chrono::milliseconds>(Now - m_LastReportTime).count();
		LOG("Preparing spawn (%s): %.02f%% (%d/%d; %.02f chunks / sec)",
			m_World.GetName().c_str(), PercentDone, m_NumPrepared, m_MaxIdx, ChunkSpeed
		);
		m_LastReportTime = Now;
		m_LastReportChunkCount = m_NumPrepared;
	}
}

<|endoftext|>