<commit_before>/*
 * Copyright (c) 2012-2016 soymuchacho <guqi_282@126.com>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * > LIBSHARED  VERSION 		:		0.0.1
 * > File Name					:		ObjectMgr.hpp
 * > Author						:		soymuchacho
 * > Created Time				:		2015-10
 * > brief						:
 *
 * */

#ifndef UTILITY_OBJECT_MGR_H
#define UTILITY_OBJECT_MGR_H

#include <tr1/memory>
#include <ext/hash_map>
#include <base/Mutex.h>
#include <network/MemoryPool.h>

namespace Shared
{

namespace Utility
{
///////////////////////////////////////////////
//	@brief	管理集合：用于对象管理。
//			线程安全, 不可重入，重入会造成死锁
///////////////////////////////////////////////

template<class Key,class Value>
class ObjectMgr
{
public:
	ObjectMgr(){

	}
	virtual ~ObjectMgr(){

	}
public:
	// Typdef
	typedef std::tr1::shared_ptr<Value> value_sptr;
	typedef typename __gnu_cxx::hash_map<Key,value_sptr>::iterator Iterator;
public:
	/**
	 *	@brief 向集合中添加一个对象。
	 *
	 *	@param k	[in] 关键字
	 *	@param val	[in] 对象指针，该指针必须是由
	 *					 系统堆分配的内存。如果是
	 *					 本库的内存池分配，请使用
	 *					 楼下函数。
	 *	@param isUseSP [in] 是否使用了libshared库的内存池（memorypool）
	 *						默认为不使用，如若使用，请设置为true。
	 *
	 *	@return true	添加成功
	 *			false	添加失败
	 *
	 **/
	bool Append(Key k,Value * v,bool isUseMP = false)
	{
		MutexLockGuard lock(&m_mutex);

		value_sptr val;

		if(isUseMP)
			val.reset(v,SHARED_DELETE<Value>());
		else
			val.reset(v);

		Iterator itr = m_objmap.find(k);

		if(itr != m_objmap.end())
			return false;
		else
		{
			m_objmap.insert(make_pair(k,val));
		}
		return true;
	}

	// 从管理集合中获取一个对象
	bool Get(Key k,value_sptr& sptr)
	{
		MutexLockGuard lock(&m_mutex);

		Iterator itr = m_objmap.find(k);

		if(itr != m_objmap.end())
		{
			sptr = itr->second;
			return true;
		}

		return false;
	}

	// 从管理集合中取出一个对象
	bool Fetch(Key k, value_sptr& sptr)
	{
		MutexLockGuard lock(&m_mutex);

		Iterator itr = m_objmap.find(k);

		if(itr == m_objmap.end())
			return false;

		sptr = itr->second;
		m_objmap.erase(itr);

		return true;
	}

	// 将对象从管理集合中移除
	bool Remove(Key k)
	{
		MutexLockGuard lock(&m_mutex);

		Iterator itr = m_objmap.find(k);

		if(itr == m_objmap.end())
			return false;

		itr->second.reset();
		m_objmap.erase(itr);

		return true;
	}

	// 清除所有对象
	void Clear()
	{
		MutexLockGuard lock(&m_mutex);
		Iterator itr;
		for(itr = m_objmap.begin(); itr != m_objmap.end(); )
		{
			itr->second.reset();
			m_objmap.erase(itr++);
		}
	}
private:
	mutable Mutex m_mutex;	// 锁
	// hash map使用key和智能指针
	__gnu_cxx::hash_map<Key,value_sptr> m_objmap;
};

}// END NAMESPACE UTILITY

}// END NAMESPACE SHARED
#endif
<commit_msg>增加遍历函数<commit_after>/*
 * Copyright (c) 2012-2016 soymuchacho <guqi_282@126.com>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * > LIBSHARED  VERSION 		:		0.0.1
 * > File Name					:		ObjectMgr.hpp
 * > Author						:		soymuchacho
 * > Created Time				:		2015-10
 * > brief						:
 *
 * */

#ifndef UTILITY_OBJECT_MGR_H
#define UTILITY_OBJECT_MGR_H

#include <tr1/memory>
#include <ext/hash_map>
#include <base/Mutex.h>
#include <network/MemoryPool.h>
#include <functional>

namespace Shared
{

namespace Utility
{
///////////////////////////////////////////////
//	@brief	管理集合：用于对象管理。
//			线程安全, 不可重入，重入会造成死锁
///////////////////////////////////////////////

template<class Key,class Value>
class ObjectMgr
{
public:
	ObjectMgr(){

	}
	virtual ~ObjectMgr(){

	}
public:
	// Typdef
	typedef std::tr1::shared_ptr<Value> value_sptr;
	typedef typename __gnu_cxx::hash_map<Key,value_sptr>::iterator Iterator;
public:
	/**
	 *	@brief 向集合中添加一个对象。
	 *
	 *	@param k	[in] 关键字
	 *	@param val	[in] 对象指针，该指针必须是由
	 *					 系统堆分配的内存。如果是
	 *					 本库的内存池分配，请使用
	 *					 楼下函数。
	 *	@param isUseSP [in] 是否使用了libshared库的内存池（memorypool）
	 *						默认为不使用，如若使用，请设置为true。
	 *
	 *	@return true	添加成功
	 *			false	添加失败
	 *
	 **/
	bool Append(Key k,Value * v,bool isUseMP = false)
	{
		MutexLockGuard lock(&m_mutex);

		value_sptr val;

		// 返回失败
		if(isUseMP)
			val.reset(v,SHARED_DELETE<Value>());
		else
			val.reset(v);

		Iterator itr = m_objmap.find(k);

		if(itr != m_objmap.end())
			return false;
		else
		{
			m_objmap.insert(make_pair(k,val));
		}
		return true;
	}

	// 从管理集合中获取一个对象
	bool Get(Key k,value_sptr& sptr)
	{
		MutexLockGuard lock(&m_mutex);

		Iterator itr = m_objmap.find(k);

		if(itr != m_objmap.end())
		{
			sptr = itr->second;
			return true;
		}

		return false;
	}

	// 从管理集合中取出一个对象
	bool Fetch(Key k, value_sptr& sptr)
	{
		MutexLockGuard lock(&m_mutex);

		Iterator itr = m_objmap.find(k);

		if(itr == m_objmap.end())
			return false;

		sptr = itr->second;
		m_objmap.erase(itr);

		return true;
	}

	// 将对象从管理集合中移除
	bool Remove(Key k)
	{
		MutexLockGuard lock(&m_mutex);

		Iterator itr = m_objmap.find(k);

		if(itr == m_objmap.end())
			return false;

		itr->second.reset();
		m_objmap.erase(itr);

		return true;
	}

	// 清除所有对象
	void Clear()
	{
		MutexLockGuard lock(&m_mutex);
		Iterator itr;
		for(itr = m_objmap.begin(); itr != m_objmap.end(); )
		{
			itr->second.reset();
			m_objmap.erase(itr++);
		}
	}
public:
	/**< @brief 遍历，传入回调函数 >*/
	void Travalcall(std::function<bool (Key,value_sptr)> callback)
	{
		MutexLockGuard lock(&m_mutex);
		Iterator itr;
		for(itr = m_objmap.begin(); itr != m_objmap.end(); itr++)
		{
			if(callback(itr->first,itr->second))
				continue;
			else
				return ;
		}
	}

	template<class P1>
	void Travalcall(std::function<bool (Key,value_sptr,P1)> callback,P1 p1)
	{
		MutexLockGuard lock(&m_mutex);
		Iterator itr;
		for(itr = m_objmap.begin(); itr != m_objmap.end(); itr++)
		{
			if(callback(itr->first,itr->second,p1))
				continue;
			else
				return ;
		}
	}

	template<class P1,class P2>
	void Travalcall(std::function<void (Key,value_sptr,P1)> callback,P1 p1,P2 p2)
	{
		MutexLockGuard lock(&m_mutex);
		Iterator itr;
		for(itr = m_objmap.begin(); itr != m_objmap.end(); itr++)
		{
			if(callback(itr->first,itr->second,p1,p2))
				continue;
			else
				return ;
		}
	}

	template<class P1,class P2,class P3>
	void Travalcall(std::function<void (Key,value_sptr,P1,P2,P3)> callback,P1 p1, P2 p2,P3 p3)
	{
		MutexLockGuard lock(&m_mutex);
		Iterator itr;
		for(itr = m_objmap.begin(); itr != m_objmap.end(); itr++)
		{
			if(callback(itr->first,itr->second,p1,p2,p3))
				continue;
			else
				return ;
		}
	}
private:
	mutable Mutex m_mutex;	// 锁
	// hash map使用key和智能指针
	__gnu_cxx::hash_map<Key,value_sptr> m_objmap;
};

}// END NAMESPACE UTILITY

}// END NAMESPACE SHARED
#endif
<|endoftext|>


<commit_before>#include "instanciate.h"

using namespace Yuni;

namespace Nany
{
namespace Pass
{
namespace Instanciate
{

	namespace // anonymous
	{

		void pragmaBodyStart(SequenceBuilder& seq)
		{
			assert(seq.frame != nullptr);
			assert(not seq.signatureOnly);
			assert(seq.codeGenerationLock == 0 and "any good reason to not generate code ?");
			assert(seq.out != nullptr and "no output IR sequence");

			auto& frame = *seq.frame;
			auto& atom = frame.atom;
			if (not atom.isFunction())
				return;

			bool generateCode = seq.canGenerateCode();
			uint32_t count = atom.parameters.size();

			atom.parameters.each([&](uint32_t i, const AnyString& name, const Vardef& vardef)
			{
				// lvid for the given parameter
				uint32_t lvid  = i + 1 + 1; // 1: return type, 2: first parameter
				assert(lvid < frame.lvids.size());
				// Obviously, the parameters are not synthetic objects
				// but real variables
				frame.lvids[lvid].synthetic = false;

				//
				// Parameters Deep copy (if required)
				//
				if (name[0] != '^')
				{
					// normal input parameter (not captured - does not start with '^')
					// clone it if necessary (only non-ref parameters)

					if (not seq.cdeftable.classdef(vardef.clid).qualifiers.ref)
					{
						if (debugmode and generateCode)
							seq.out->emitComment(String{"----- deep copy parameter "} << i << " aka " << name);

						// a register has already been reserved for cloning parameters
						uint32_t clone = 2 + count + i; // 1: return type, 2: first parameter
						assert(clone < frame.lvids.size());
						// the new value is not synthetic
						frame.lvids[clone].synthetic = false;

						bool r = seq.instanciateAssignment(frame, clone, lvid, false, false, true);
						if (unlikely(not r))
							frame.invalidate(clone);

						if (seq.canBeAcquired(lvid))
						{
							frame.lvids[lvid].autorelease = true;
							frame.lvids[clone].autorelease = false;
						}

						if (generateCode)
						{
							seq.out->emitStore(lvid, clone); // register swap
							if (debugmode)
								seq.out->emitComment("--\n");
						}
					}
				}
			});

			// generating some code on the fly
			if (atom.isSpecial() /*ctor, operators...*/ and generateCode)
			{
				// variables initialization (for a ctor)
				if (seq.generateClassVarsAutoInit)
				{
					seq.generateClassVarsAutoInit = false;
					seq.generateMemberVarDefaultInitialization();
				}

				// variables destruction (for dtor)
				if (seq.generateClassVarsAutoRelease)
				{
					seq.generateClassVarsAutoRelease = false;
					seq.generateMemberVarDefaultDispose();
				}

				// variables cloning (copy a ctor)
				if (seq.generateClassVarsAutoClone)
				{
					seq.generateClassVarsAutoClone = false;
					seq.generateMemberVarDefaultClone();
				}
			}
		}

		void pragmaCodegen(SequenceBuilder& seq, bool onoff)
		{
			auto& refcount = seq.codeGenerationLock;
			if (onoff)
			{
				if (refcount > 0) // re-enable code generation
					--refcount;
			}
			else
				++refcount;
		}

	} // anonymous namespace

	void SequenceBuilder::visit(const IR::ISA::Operand<IR::ISA::Op::pragma>& operands)
	{
		assert(static_cast<uint32_t>(operands.pragma) < IR::ISA::PragmaCount);

		auto pragma = static_cast<IR::ISA::Pragma>(operands.pragma);
		switch (pragma)
		{
			case IR::ISA::Pragma::codegen:
			{
				pragmaCodegen(*this, operands.value.codegen != 0);
				break;
			}
			case IR::ISA::Pragma::bodystart:
			{
				// In 'signature only' mode, we only care about the
				// parameter user types. Everything from this point in unrelevant
				if (signatureOnly)
					currentSequence.invalidateCursor(*cursor);
				else
					pragmaBodyStart(*this); // params deep copy, implicit var auto-init...
				break;
			}

			case IR::ISA::Pragma::blueprintsize:
			{
				if (0 == layerDepthLimit)
				{
					// ignore the current blueprint
					//*cursor += operands.value.blueprintsize;
					assert(frame != nullptr);
					assert(frame->offsetOpcodeBlueprint != (uint32_t) -1);
					auto startOffset = frame->offsetOpcodeBlueprint;
					uint32_t count = operands.value.blueprintsize;

					if (unlikely(count < 3))
					{
						ice() << "invalid blueprint size when instanciating atom";
						break;
					}

					// goto the end of the blueprint
					// -2: the final 'end' opcode must be interpreted
					*cursor = &currentSequence.at(startOffset + count - 1 - 1);
				}
				break;
			}

			case IR::ISA::Pragma::visibility:
			{
				assert(frame != nullptr);
				break;
			}

			case IR::ISA::Pragma::shortcircuitOpNopOffset:
			{
				shortcircuit.label = operands.value.shortcircuitMetadata.label;
				break;
			}

			case IR::ISA::Pragma::shortcircuitMutateToBool:
			{
				uint32_t lvid = operands.value.shortcircuitMutate.lvid;
				uint32_t source = operands.value.shortcircuitMutate.source;

				frame->lvids[lvid].synthetic = false;

				if (true)
				{
					auto& instr = *(*cursor - 1);
					assert(instr.opcodes[0] == static_cast<uint32_t>(IR::ISA::Op::stackalloc));
					uint32_t sizeoflvid = instr.to<IR::ISA::Op::stackalloc>().lvid;

					// sizeof
					auto& atombool = *(cdeftable.atoms().core.object[nyt_bool]);
					out->emitSizeof(sizeoflvid, atombool.atomid);

					auto& opc = cdeftable.substitute(lvid);
					opc.mutateToAtom(&atombool);
					opc.qualifiers.ref = true;

					// ALLOC: memory allocation of the new temporary object
					out->emitMemalloc(lvid, sizeoflvid);
					out->emitRef(lvid);
					frame->lvids[lvid].autorelease = true;
					// reset the internal value of the object
					out->emitFieldset(source, /*self*/lvid, 0); // builtin
				}
				else
					out->emitStore(lvid, source);
				break;
			}

			case IR::ISA::Pragma::synthetic:
			{
				uint32_t lvid = operands.value.synthetic.lvid;
				bool onoff = (operands.value.synthetic.onoff != 0);
				frame->lvids[lvid].synthetic = onoff;
				break;
			}

			case IR::ISA::Pragma::suggest:
			case IR::ISA::Pragma::builtinalias:
			case IR::ISA::Pragma::shortcircuit:
			case IR::ISA::Pragma::unknown:
				break;
		}
	}

} // namespace Instanciate
} // namespace Pass
} // namespace Nany
<commit_msg>instanciate: isolated pragma blueprintsize<commit_after>#include "instanciate.h"

using namespace Yuni;

namespace Nany
{
namespace Pass
{
namespace Instanciate
{

	namespace // anonymous
	{

		void pragmaBodyStart(SequenceBuilder& seq)
		{
			assert(seq.frame != nullptr);
			assert(not seq.signatureOnly);
			assert(seq.codeGenerationLock == 0 and "any good reason to not generate code ?");
			assert(seq.out != nullptr and "no output IR sequence");

			auto& frame = *seq.frame;
			auto& atom = frame.atom;
			if (not atom.isFunction())
				return;

			bool generateCode = seq.canGenerateCode();
			uint32_t count = atom.parameters.size();

			atom.parameters.each([&](uint32_t i, const AnyString& name, const Vardef& vardef)
			{
				// lvid for the given parameter
				uint32_t lvid  = i + 1 + 1; // 1: return type, 2: first parameter
				assert(lvid < frame.lvids.size());
				// Obviously, the parameters are not synthetic objects
				// but real variables
				frame.lvids[lvid].synthetic = false;

				//
				// Parameters Deep copy (if required)
				//
				if (name[0] != '^')
				{
					// normal input parameter (not captured - does not start with '^')
					// clone it if necessary (only non-ref parameters)

					if (not seq.cdeftable.classdef(vardef.clid).qualifiers.ref)
					{
						if (debugmode and generateCode)
							seq.out->emitComment(String{"----- deep copy parameter "} << i << " aka " << name);

						// a register has already been reserved for cloning parameters
						uint32_t clone = 2 + count + i; // 1: return type, 2: first parameter
						assert(clone < frame.lvids.size());
						// the new value is not synthetic
						frame.lvids[clone].synthetic = false;

						bool r = seq.instanciateAssignment(frame, clone, lvid, false, false, true);
						if (unlikely(not r))
							frame.invalidate(clone);

						if (seq.canBeAcquired(lvid))
						{
							frame.lvids[lvid].autorelease = true;
							frame.lvids[clone].autorelease = false;
						}

						if (generateCode)
						{
							seq.out->emitStore(lvid, clone); // register swap
							if (debugmode)
								seq.out->emitComment("--\n");
						}
					}
				}
			});

			// generating some code on the fly
			if (atom.isSpecial() /*ctor, operators...*/ and generateCode)
			{
				// variables initialization (for a ctor)
				if (seq.generateClassVarsAutoInit)
				{
					seq.generateClassVarsAutoInit = false;
					seq.generateMemberVarDefaultInitialization();
				}

				// variables destruction (for dtor)
				if (seq.generateClassVarsAutoRelease)
				{
					seq.generateClassVarsAutoRelease = false;
					seq.generateMemberVarDefaultDispose();
				}

				// variables cloning (copy a ctor)
				if (seq.generateClassVarsAutoClone)
				{
					seq.generateClassVarsAutoClone = false;
					seq.generateMemberVarDefaultClone();
				}
			}
		}

		void pragmaCodegen(SequenceBuilder& seq, bool onoff)
		{
			auto& refcount = seq.codeGenerationLock;
			if (onoff)
			{
				if (refcount > 0) // re-enable code generation
					--refcount;
			}
			else
				++refcount;
		}

		void pragmaBlueprintSize(SequenceBuilder& seq, uint32_t opcodeCount)
		{
			if (0 == seq.layerDepthLimit)
			{
				// ignore the current blueprint
				//*cursor += operands.value.blueprintsize;
				assert(seq.frame != nullptr);
				assert(seq.frame->offsetOpcodeBlueprint != (uint32_t) -1);
				auto startOffset = seq.frame->offsetOpcodeBlueprint;
				if (unlikely(opcodeCount < 3))
					return (void) (ice() << "invalid blueprint size when instanciating atom");

				// goto the end of the blueprint
				// -2: the final 'end' opcode must be interpreted
				*seq.cursor = &seq.currentSequence.at(startOffset + opcodeCount - 1 - 1);
			}
		}

	} // anonymous namespace

	void SequenceBuilder::visit(const IR::ISA::Operand<IR::ISA::Op::pragma>& operands)
	{
		assert(static_cast<uint32_t>(operands.pragma) < IR::ISA::PragmaCount);

		auto pragma = static_cast<IR::ISA::Pragma>(operands.pragma);
		switch (pragma)
		{
			case IR::ISA::Pragma::codegen:
			{
				pragmaCodegen(*this, operands.value.codegen != 0);
				break;
			}
			case IR::ISA::Pragma::bodystart:
			{
				// In 'signature only' mode, we only care about the
				// parameter user types. Everything from this point in unrelevant
				if (signatureOnly)
					currentSequence.invalidateCursor(*cursor);
				else
					pragmaBodyStart(*this); // params deep copy, implicit var auto-init...
				break;
			}
			case IR::ISA::Pragma::blueprintsize:
			{
				pragmaBlueprintSize(*this, operands.value.blueprintsize);
				break;
			}

			case IR::ISA::Pragma::visibility:
			{
				assert(frame != nullptr);
				break;
			}

			case IR::ISA::Pragma::shortcircuitOpNopOffset:
			{
				shortcircuit.label = operands.value.shortcircuitMetadata.label;
				break;
			}

			case IR::ISA::Pragma::shortcircuitMutateToBool:
			{
				uint32_t lvid = operands.value.shortcircuitMutate.lvid;
				uint32_t source = operands.value.shortcircuitMutate.source;

				frame->lvids[lvid].synthetic = false;

				if (true)
				{
					auto& instr = *(*cursor - 1);
					assert(instr.opcodes[0] == static_cast<uint32_t>(IR::ISA::Op::stackalloc));
					uint32_t sizeoflvid = instr.to<IR::ISA::Op::stackalloc>().lvid;

					// sizeof
					auto& atombool = *(cdeftable.atoms().core.object[nyt_bool]);
					out->emitSizeof(sizeoflvid, atombool.atomid);

					auto& opc = cdeftable.substitute(lvid);
					opc.mutateToAtom(&atombool);
					opc.qualifiers.ref = true;

					// ALLOC: memory allocation of the new temporary object
					out->emitMemalloc(lvid, sizeoflvid);
					out->emitRef(lvid);
					frame->lvids[lvid].autorelease = true;
					// reset the internal value of the object
					out->emitFieldset(source, /*self*/lvid, 0); // builtin
				}
				else
					out->emitStore(lvid, source);
				break;
			}

			case IR::ISA::Pragma::synthetic:
			{
				uint32_t lvid = operands.value.synthetic.lvid;
				bool onoff = (operands.value.synthetic.onoff != 0);
				frame->lvids[lvid].synthetic = onoff;
				break;
			}

			case IR::ISA::Pragma::suggest:
			case IR::ISA::Pragma::builtinalias:
			case IR::ISA::Pragma::shortcircuit:
			case IR::ISA::Pragma::unknown:
				break;
		}
	}

} // namespace Instanciate
} // namespace Pass
} // namespace Nany
<|endoftext|>


<commit_before>#include <cerrno>
#include <iostream>

#include <libport/assert.hh>
#include <libport/exception.hh>
#include <libport/program-name.hh>
#include <libport/semaphore.hh>
#include <libport/sysexits.hh>
#include <libport/time.h>

/* Darwin doesn't implement sem_init/sem_close (although the functions exists
 * and is defined, in fact it just returns ENOSYS). That's why we need to use
 * named semaphores (with sem_open) instead.
 * See:
 * http://lists.apple.com/archives/darwin-development/2004/May/msg00077.html
 * http://www.google.com/search?as_q=sem_init&as_sitesearch=apple.com
 *
 * Semaphores created with sem_open must be closed with sem_close.
 * Semaphores created with sem_init must be closed with sem_destroy.
 */
#ifdef __APPLE__
# include <fstream>
# include <sstream>
# include <sys/stat.h>
# include <sys/time.h>
# include <signal.h>
#endif

namespace libport
{

  Semaphore::Semaphore(unsigned value)
    : value_(value)
  {
# ifdef __APPLE__
    static unsigned int counter = 0;
    int sem_open_errno;

    do
    {
      std::stringstream s;
      errno = 0;
      s << "sema/" << getpid() << "/" << counter++;
      name_ = s.str();
      sem_ = sem_open(name_.c_str(), O_CREAT | O_EXCL, 0777, value);
      sem_open_errno = errno;
    } while (sem_ == SEM_FAILED && errno == EEXIST);

    {
      // Save the semaphore name if we can, in order to provide the
      // user with a means to reclaim them.  Don't check for success,
      // this is best effort.
      //
      // If you change this file name, update
      // build-aux/semaphores-clean.sh.
      mkdir("/tmp/urbi-semaphores", 0777);
      std::stringstream f;
      f << "/tmp/urbi-semaphores/" << getpid();
      std::ofstream o(f.str().c_str(), std::ios_base::app);
      o << name_;
      if (sem_ == SEM_FAILED)
        o << ": " << strerror(sem_open_errno);
      o << std::endl;
    }

    if (sem_ == SEM_FAILED)
    {
      std::string error = strerror(sem_open_errno);
      if (sem_open_errno == ENOSPC)
        error += " (i.e., used all the semaphores, run semaphore-clean)";
      // Certainly dying because we don't have enough semaphores
      // available.  Report we should be skipped.
      std::cerr << program_name()
                << ": cannot sem_open(" << name_ << "): "
                << strerror(sem_open_errno)
                << std::endl
                << exit(EX_SKIP);
    }
# else
    sem_ = new sem_t;
    if (sem_init(sem_, 0, value))
    {
      destroy();
      errabort("sem_init(" << value << ')');
    }
# endif
    ++instances_;
  }

  Semaphore::~Semaphore()
  {
    destroy();
    --instances_;
  }

  size_t Semaphore::instances_ = 0;

  size_t
  Semaphore::instances()
  {
    return instances_;
  }

  void
  Semaphore::destroy()
  {
# ifdef __APPLE__
    // We *really* need to unlink the semaphores when we are done,
    // otherwise they leak, and at some point, ENOSPCE is the only
    // answer from the system.  I could not find a means to remove
    // them from the shell (ipcs shows nothing), so I had to reboot my
    // machine.
    //
    // So really, try to call sem_unlink in all the cases, including
    // aborts here.
    //
    // http://lists.apple.com/archives/darwin-dev/2005/Jun/msg00078.html
    int c = sem_close(sem_);
    int close_errno = errno;
    int u = sem_unlink(name_.c_str());
    int unlink_errno = errno;
    if (c)
    {
      errno = close_errno;
      errabort("sem_close");
    }
    if (u)
    {
      errno = unlink_errno;
      errabort("sem_unlink");
    }
# else
    if (sem_destroy(sem_))
      errabort("sem_destroy");
    delete sem_;
# endif
  }

  void
  Semaphore::operator++()
  {
    if (sem_post(sem_))
    {
      destroy();
      errabort("sem_post");
    }
    ++value_;
  }

  void
  Semaphore::operator--()
  {
    get(0);
  }

  Semaphore& Semaphore::operator-=(unsigned c)
  {
    for (unsigned i = 0; i < c; ++i)
      --*this;
    return *this;
  }

  Semaphore& Semaphore::operator+=(unsigned c)
  {
    for (unsigned i = 0; i < c; ++i)
      ++*this;
    return *this;
  }

# if defined __APPLE__

  // On OSX there seems to be no means to timeout passively, so we
  // launch a thread that will change the following flag when the time
  // is out.
  static bool time_is_out;

  void fun_timeout(int)
  {
    time_is_out = true;
  }

# endif

  bool
  Semaphore::uget(utime_t useconds)
  {
    int err;
    do
    {
      if (useconds == 0)
        err = sem_wait(sem_);
# if defined __APPLE__
      else
      {
	struct itimerval it;
	it.it_interval.tv_sec = 0;
	it.it_interval.tv_usec = 0;

	it.it_value.tv_sec = useconds / 1000000;
	it.it_value.tv_usec = useconds % 1000000;
	time_is_out = false;
	signal(SIGALRM, fun_timeout);
	setitimer(ITIMER_REAL, &it, NULL);
	do
	{
	  err = sem_trywait(sem_);
	} while (!time_is_out && err == -1 && errno == EAGAIN);
	if (time_is_out)
        {
          // Match the interface under Linux.
	  err = -1;
          errno = ETIMEDOUT;
        }
      }
# else
      else
      {
        struct timespec ts;
	if (clock_gettime(CLOCK_REALTIME, &ts))
          errabort("clock_gettime");
	ts.tv_sec += useconds / 1000000;
	ts.tv_nsec += (useconds % 1000000) * 1000;
        err = sem_timedwait(sem_, &ts);
      }
# endif
    }
    while (err == -1 && errno == EINTR);

    if (err)
    {
      if (errno == ETIMEDOUT)
        return false;
      destroy();
      errabort("sem_wait");
    }

    --value_;
    return true;
  }

  bool
  Semaphore::get(unsigned seconds)
  {
    return uget(seconds * 1000 * 1000);
  }

  Semaphore::operator int()
  {
#ifndef __APPLE__
    int res;
    if (sem_getvalue(sem_, &res))
    {
      destroy();
      errabort("sem_getvalue");
    }
    assert_eq(res, value_);
#endif
    return value_;
  }

} // namespace libport
<commit_msg>libport: don't overflow timespec.<commit_after>#include <cerrno>
#include <iostream>

#include <libport/assert.hh>
#include <libport/exception.hh>
#include <libport/program-name.hh>
#include <libport/semaphore.hh>
#include <libport/sysexits.hh>
#include <libport/time.h>

/* Darwin doesn't implement sem_init/sem_close (although the functions exists
 * and is defined, in fact it just returns ENOSYS). That's why we need to use
 * named semaphores (with sem_open) instead.
 * See:
 * http://lists.apple.com/archives/darwin-development/2004/May/msg00077.html
 * http://www.google.com/search?as_q=sem_init&as_sitesearch=apple.com
 *
 * Semaphores created with sem_open must be closed with sem_close.
 * Semaphores created with sem_init must be closed with sem_destroy.
 */
#ifdef __APPLE__
# include <fstream>
# include <sstream>
# include <sys/stat.h>
# include <sys/time.h>
# include <signal.h>
#endif

namespace libport
{

  Semaphore::Semaphore(unsigned value)
    : value_(value)
  {
# ifdef __APPLE__
    static unsigned int counter = 0;
    int sem_open_errno;

    do
    {
      std::stringstream s;
      errno = 0;
      s << "sema/" << getpid() << "/" << counter++;
      name_ = s.str();
      sem_ = sem_open(name_.c_str(), O_CREAT | O_EXCL, 0777, value);
      sem_open_errno = errno;
    } while (sem_ == SEM_FAILED && errno == EEXIST);

    {
      // Save the semaphore name if we can, in order to provide the
      // user with a means to reclaim them.  Don't check for success,
      // this is best effort.
      //
      // If you change this file name, update
      // build-aux/semaphores-clean.sh.
      mkdir("/tmp/urbi-semaphores", 0777);
      std::stringstream f;
      f << "/tmp/urbi-semaphores/" << getpid();
      std::ofstream o(f.str().c_str(), std::ios_base::app);
      o << name_;
      if (sem_ == SEM_FAILED)
        o << ": " << strerror(sem_open_errno);
      o << std::endl;
    }

    if (sem_ == SEM_FAILED)
    {
      std::string error = strerror(sem_open_errno);
      if (sem_open_errno == ENOSPC)
        error += " (i.e., used all the semaphores, run semaphore-clean)";
      // Certainly dying because we don't have enough semaphores
      // available.  Report we should be skipped.
      std::cerr << program_name()
                << ": cannot sem_open(" << name_ << "): "
                << strerror(sem_open_errno)
                << std::endl
                << exit(EX_SKIP);
    }
# else
    sem_ = new sem_t;
    if (sem_init(sem_, 0, value))
    {
      destroy();
      errabort("sem_init(" << value << ')');
    }
# endif
    ++instances_;
  }

  Semaphore::~Semaphore()
  {
    destroy();
    --instances_;
  }

  size_t Semaphore::instances_ = 0;

  size_t
  Semaphore::instances()
  {
    return instances_;
  }

  void
  Semaphore::destroy()
  {
# ifdef __APPLE__
    // We *really* need to unlink the semaphores when we are done,
    // otherwise they leak, and at some point, ENOSPCE is the only
    // answer from the system.  I could not find a means to remove
    // them from the shell (ipcs shows nothing), so I had to reboot my
    // machine.
    //
    // So really, try to call sem_unlink in all the cases, including
    // aborts here.
    //
    // http://lists.apple.com/archives/darwin-dev/2005/Jun/msg00078.html
    int c = sem_close(sem_);
    int close_errno = errno;
    int u = sem_unlink(name_.c_str());
    int unlink_errno = errno;
    if (c)
    {
      errno = close_errno;
      errabort("sem_close");
    }
    if (u)
    {
      errno = unlink_errno;
      errabort("sem_unlink");
    }
# else
    if (sem_destroy(sem_))
      errabort("sem_destroy");
    delete sem_;
# endif
  }

  void
  Semaphore::operator++()
  {
    if (sem_post(sem_))
    {
      destroy();
      errabort("sem_post");
    }
    ++value_;
  }

  void
  Semaphore::operator--()
  {
    get(0);
  }

  Semaphore& Semaphore::operator-=(unsigned c)
  {
    for (unsigned i = 0; i < c; ++i)
      --*this;
    return *this;
  }

  Semaphore& Semaphore::operator+=(unsigned c)
  {
    for (unsigned i = 0; i < c; ++i)
      ++*this;
    return *this;
  }

# if defined __APPLE__

  // On OSX there seems to be no means to timeout passively, so we
  // launch a thread that will change the following flag when the time
  // is out.
  static bool time_is_out;

  void fun_timeout(int)
  {
    time_is_out = true;
  }

# endif

  bool
  Semaphore::uget(utime_t useconds)
  {
    int err;
    do
    {
      if (useconds == 0)
        err = sem_wait(sem_);
# if defined __APPLE__
      else
      {
	struct itimerval it;
	it.it_interval.tv_sec = 0;
	it.it_interval.tv_usec = 0;

	it.it_value.tv_sec = useconds / 1000000;
	it.it_value.tv_usec = useconds % 1000000;
	time_is_out = false;
	signal(SIGALRM, fun_timeout);
	setitimer(ITIMER_REAL, &it, NULL);
	do
	{
	  err = sem_trywait(sem_);
	} while (!time_is_out && err == -1 && errno == EAGAIN);
	if (time_is_out)
        {
          // Match the interface under Linux.
	  err = -1;
          errno = ETIMEDOUT;
        }
      }
# else
      else
      {
        struct timespec ts;
        if (clock_gettime(CLOCK_REALTIME, &ts))
          errabort("clock_gettime");
        ts.tv_sec += useconds / (1000 * 1000);
        ts.tv_nsec += (useconds % (1000 * 1000)) * 1000;
        // Respect the constrainsts.
        ts.tv_sec += ts.tv_nsec / (1000 * 1000 * 1000);
        ts.tv_nsec %= 1000 * 1000 * 1000;
        err = sem_timedwait(sem_, &ts);
      }
# endif
    }
    while (err == -1 && errno == EINTR);

    if (err)
    {
      if (errno == ETIMEDOUT)
        return false;
      destroy();
      errabort("sem_wait");
    }

    --value_;
    return true;
  }

  bool
  Semaphore::get(unsigned seconds)
  {
    return uget(seconds * 1000 * 1000);
  }

  Semaphore::operator int()
  {
#ifndef __APPLE__
    int res;
    if (sem_getvalue(sem_, &res))
    {
      destroy();
      errabort("sem_getvalue");
    }
    assert_eq(res, value_);
#endif
    return value_;
  }

} // namespace libport
<|endoftext|>


<commit_before>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

#include <algorithm>
#include <iostream>

#include "TSocketPool.h"

namespace apache { namespace thrift { namespace transport {

using namespace std;

using boost::shared_ptr;

/**
 * TSocketPoolServer implementation
 *
 */
TSocketPoolServer::TSocketPoolServer()
  : host_(""),
    port_(0),
    socket_(-1),
    lastFailTime_(0),
    consecutiveFailures_(0) {}

/**
 * Constructor for TSocketPool server
 */
TSocketPoolServer::TSocketPoolServer(const string &host, int port)
  : host_(host),
    port_(port),
    socket_(-1),
    lastFailTime_(0),
    consecutiveFailures_(0) {}

/**
 * TSocketPool implementation.
 *
 */

TSocketPool::TSocketPool() : TSocket(),
  numRetries_(1),
  retryInterval_(60),
  maxConsecutiveFailures_(1),
  randomize_(true),
  alwaysTryLast_(true) {
}

TSocketPool::TSocketPool(const vector<string> &hosts,
                         const vector<int> &ports) : TSocket(),
  numRetries_(1),
  retryInterval_(60),
  maxConsecutiveFailures_(1),
  randomize_(true),
  alwaysTryLast_(true)
{
  if (hosts.size() != ports.size()) {
    GlobalOutput("TSocketPool::TSocketPool: hosts.size != ports.size");
    throw TTransportException(TTransportException::BAD_ARGS);
  }

  for (unsigned int i = 0; i < hosts.size(); ++i) {
    addServer(hosts[i], ports[i]);
  }
}

TSocketPool::TSocketPool(const vector<pair<string, int> >& servers) : TSocket(),
  numRetries_(1),
  retryInterval_(60),
  maxConsecutiveFailures_(1),
  randomize_(true),
  alwaysTryLast_(true)
{
  for (unsigned i = 0; i < servers.size(); ++i) {
    addServer(servers[i].first, servers[i].second);
  }
}

TSocketPool::TSocketPool(const vector< shared_ptr<TSocketPoolServer> >& servers) : TSocket(),
  servers_(servers),
  numRetries_(1),
  retryInterval_(60),
  maxConsecutiveFailures_(1),
  randomize_(true),
  alwaysTryLast_(true)
{
}

TSocketPool::TSocketPool(const string& host, int port) : TSocket(),
  numRetries_(1),
  retryInterval_(60),
  maxConsecutiveFailures_(1),
  randomize_(true),
  alwaysTryLast_(true)
{
  addServer(host, port);
}

TSocketPool::~TSocketPool() {
  vector< shared_ptr<TSocketPoolServer> >::const_iterator iter = servers_.begin();
  vector< shared_ptr<TSocketPoolServer> >::const_iterator iterEnd = servers_.end();
  for (; iter != iterEnd; ++iter) {
    setCurrentServer(*iter);
    TSocketPool::close();
  }
}

void TSocketPool::addServer(const string& host, int port) {
  servers_.push_back(shared_ptr<TSocketPoolServer>(new TSocketPoolServer(host, port)));
}

void TSocketPool::addServer(shared_ptr<TSocketPoolServer> &server) {
  if (server) {
    servers_.push_back(server);
  }
}

void TSocketPool::setServers(const vector< shared_ptr<TSocketPoolServer> >& servers) {
  servers_ = servers;
}

void TSocketPool::getServers(vector< shared_ptr<TSocketPoolServer> >& servers) {
  servers = servers_;
}

void TSocketPool::setNumRetries(int numRetries) {
  numRetries_ = numRetries;
}

void TSocketPool::setRetryInterval(int retryInterval) {
  retryInterval_ = retryInterval;
}

void TSocketPool::setMaxConsecutiveFailures(int maxConsecutiveFailures) {
  maxConsecutiveFailures_ = maxConsecutiveFailures;
}

void TSocketPool::setRandomize(bool randomize) {
  randomize_ = randomize;
}

void TSocketPool::setAlwaysTryLast(bool alwaysTryLast) {
  alwaysTryLast_ = alwaysTryLast;
}

void TSocketPool::setCurrentServer(const shared_ptr<TSocketPoolServer> &server) {
  currentServer_ = server;
  host_ = server->host_;
  port_ = server->port_;
  socket_ = server->socket_;
}

/**
 * This function throws an exception if socket open fails. When socket
 * opens fails, the socket in the current server is reset.
 */
/* TODO: without apc we ignore a lot of functionality from the php version */
void TSocketPool::open() {

  size_t numServers = servers_.size();
  if (numServers == 0) {
    socket_ = -1;
    throw TTransportException(TTransportException::NOT_OPEN);
  }

  if (isOpen()) {
    return;
  }

  if (randomize_ && numServers > 1) {
    random_shuffle(servers_.begin(), servers_.end());
  }

  for (size_t i = 0; i < numServers; ++i) {

    shared_ptr<TSocketPoolServer> &server = servers_[i];
    // Impersonate the server socket
    setCurrentServer(server);

    if (isOpen()) {
      // already open means we're done
      return;
    }

    bool retryIntervalPassed = (server->lastFailTime_ == 0);
    bool isLastServer = alwaysTryLast_ ? (i == (numServers - 1)) : false;

    if (server->lastFailTime_ > 0) {
      // The server was marked as down, so check if enough time has elapsed to retry
      time_t elapsedTime = time(NULL) - server->lastFailTime_;
      if (elapsedTime > retryInterval_) {
        retryIntervalPassed = true;
      }
    }

    if (retryIntervalPassed || isLastServer) {
      for (int j = 0; j < numRetries_; ++j) {
        try {
          TSocket::open();
        } catch (TException e) {
          string errStr = "TSocketPool::open failed "+getSocketInfo()+": "+e.what();
          GlobalOutput(errStr.c_str());
          socket_ = -1;
          continue;
        }

        // Copy over the opened socket so that we can keep it persistent
        server->socket_ = socket_;
        // reset lastFailTime_ is required
        server->lastFailTime_ = 0;
        // success
        return;
      }

      ++server->consecutiveFailures_;
      if (server->consecutiveFailures_ > maxConsecutiveFailures_) {
        // Mark server as down
        server->consecutiveFailures_ = 0;
        server->lastFailTime_ = time(NULL);
      }
    }
  }

  GlobalOutput("TSocketPool::open: all connections failed");
  throw TTransportException(TTransportException::NOT_OPEN);
}

void TSocketPool::close() {
  TSocket::close();
  if (currentServer_) {
    currentServer_->socket_ = -1;
  }
}

}}} // apache::thrift::transport
<commit_msg>THRIFT-1744: Compilation failure under Android NDK toolchain Client: C++ and Android NDK Patch: Vlad Troyanker<commit_after>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <algorithm>
#include <iostream>

#include "TSocketPool.h"

namespace apache { namespace thrift { namespace transport {

using namespace std;

using boost::shared_ptr;

/**
 * TSocketPoolServer implementation
 *
 */
TSocketPoolServer::TSocketPoolServer()
  : host_(""),
    port_(0),
    socket_(-1),
    lastFailTime_(0),
    consecutiveFailures_(0) {}

/**
 * Constructor for TSocketPool server
 */
TSocketPoolServer::TSocketPoolServer(const string &host, int port)
  : host_(host),
    port_(port),
    socket_(-1),
    lastFailTime_(0),
    consecutiveFailures_(0) {}

/**
 * TSocketPool implementation.
 *
 */

TSocketPool::TSocketPool() : TSocket(),
  numRetries_(1),
  retryInterval_(60),
  maxConsecutiveFailures_(1),
  randomize_(true),
  alwaysTryLast_(true) {
}

TSocketPool::TSocketPool(const vector<string> &hosts,
                         const vector<int> &ports) : TSocket(),
  numRetries_(1),
  retryInterval_(60),
  maxConsecutiveFailures_(1),
  randomize_(true),
  alwaysTryLast_(true)
{
  if (hosts.size() != ports.size()) {
    GlobalOutput("TSocketPool::TSocketPool: hosts.size != ports.size");
    throw TTransportException(TTransportException::BAD_ARGS);
  }

  for (unsigned int i = 0; i < hosts.size(); ++i) {
    addServer(hosts[i], ports[i]);
  }
}

TSocketPool::TSocketPool(const vector<pair<string, int> >& servers) : TSocket(),
  numRetries_(1),
  retryInterval_(60),
  maxConsecutiveFailures_(1),
  randomize_(true),
  alwaysTryLast_(true)
{
  for (unsigned i = 0; i < servers.size(); ++i) {
    addServer(servers[i].first, servers[i].second);
  }
}

TSocketPool::TSocketPool(const vector< shared_ptr<TSocketPoolServer> >& servers) : TSocket(),
  servers_(servers),
  numRetries_(1),
  retryInterval_(60),
  maxConsecutiveFailures_(1),
  randomize_(true),
  alwaysTryLast_(true)
{
}

TSocketPool::TSocketPool(const string& host, int port) : TSocket(),
  numRetries_(1),
  retryInterval_(60),
  maxConsecutiveFailures_(1),
  randomize_(true),
  alwaysTryLast_(true)
{
  addServer(host, port);
}

TSocketPool::~TSocketPool() {
  vector< shared_ptr<TSocketPoolServer> >::const_iterator iter = servers_.begin();
  vector< shared_ptr<TSocketPoolServer> >::const_iterator iterEnd = servers_.end();
  for (; iter != iterEnd; ++iter) {
    setCurrentServer(*iter);
    TSocketPool::close();
  }
}

void TSocketPool::addServer(const string& host, int port) {
  servers_.push_back(shared_ptr<TSocketPoolServer>(new TSocketPoolServer(host, port)));
}

void TSocketPool::addServer(shared_ptr<TSocketPoolServer> &server) {
  if (server) {
    servers_.push_back(server);
  }
}

void TSocketPool::setServers(const vector< shared_ptr<TSocketPoolServer> >& servers) {
  servers_ = servers;
}

void TSocketPool::getServers(vector< shared_ptr<TSocketPoolServer> >& servers) {
  servers = servers_;
}

void TSocketPool::setNumRetries(int numRetries) {
  numRetries_ = numRetries;
}

void TSocketPool::setRetryInterval(int retryInterval) {
  retryInterval_ = retryInterval;
}

void TSocketPool::setMaxConsecutiveFailures(int maxConsecutiveFailures) {
  maxConsecutiveFailures_ = maxConsecutiveFailures;
}

void TSocketPool::setRandomize(bool randomize) {
  randomize_ = randomize;
}

void TSocketPool::setAlwaysTryLast(bool alwaysTryLast) {
  alwaysTryLast_ = alwaysTryLast;
}

void TSocketPool::setCurrentServer(const shared_ptr<TSocketPoolServer> &server) {
  currentServer_ = server;
  host_ = server->host_;
  port_ = server->port_;
  socket_ = server->socket_;
}

/**
 * This function throws an exception if socket open fails. When socket
 * opens fails, the socket in the current server is reset.
 */
/* TODO: without apc we ignore a lot of functionality from the php version */
void TSocketPool::open() {

  size_t numServers = servers_.size();
  if (numServers == 0) {
    socket_ = -1;
    throw TTransportException(TTransportException::NOT_OPEN);
  }

  if (isOpen()) {
    return;
  }

  if (randomize_ && numServers > 1) {
    random_shuffle(servers_.begin(), servers_.end());
  }

  for (size_t i = 0; i < numServers; ++i) {

    shared_ptr<TSocketPoolServer> &server = servers_[i];
    // Impersonate the server socket
    setCurrentServer(server);

    if (isOpen()) {
      // already open means we're done
      return;
    }

    bool retryIntervalPassed = (server->lastFailTime_ == 0);
    bool isLastServer = alwaysTryLast_ ? (i == (numServers - 1)) : false;

    if (server->lastFailTime_ > 0) {
      // The server was marked as down, so check if enough time has elapsed to retry
      time_t elapsedTime = time(NULL) - server->lastFailTime_;
      if (elapsedTime > retryInterval_) {
        retryIntervalPassed = true;
      }
    }

    if (retryIntervalPassed || isLastServer) {
      for (int j = 0; j < numRetries_; ++j) {
        try {
          TSocket::open();
        } catch (TException e) {
          string errStr = "TSocketPool::open failed "+getSocketInfo()+": "+e.what();
          GlobalOutput(errStr.c_str());
          socket_ = -1;
          continue;
        }

        // Copy over the opened socket so that we can keep it persistent
        server->socket_ = socket_;
        // reset lastFailTime_ is required
        server->lastFailTime_ = 0;
        // success
        return;
      }

      ++server->consecutiveFailures_;
      if (server->consecutiveFailures_ > maxConsecutiveFailures_) {
        // Mark server as down
        server->consecutiveFailures_ = 0;
        server->lastFailTime_ = time(NULL);
      }
    }
  }

  GlobalOutput("TSocketPool::open: all connections failed");
  throw TTransportException(TTransportException::NOT_OPEN);
}

void TSocketPool::close() {
  TSocket::close();
  if (currentServer_) {
    currentServer_->socket_ = -1;
  }
}

}}} // apache::thrift::transport
<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/memory/lib/workarounds/dp16_workarounds.H $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2016,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

///
/// @file workarounds/dp16.H
/// @brief Workarounds for the DP16 logic blocks
/// Workarounds are very deivce specific, so there is no attempt to generalize
/// this code in any way.
///
// *HWP HWP Owner: Brian Silver <bsilver@us.ibm.com>
// *HWP HWP Backup: Steven Glancy <sglancy@usi.ibm.com>
// *HWP Team: Memory
// *HWP Level: 2
// *HWP Consumed by: FSP:HB

#ifndef _MSS_WORKAROUNDS_DP16_H_
#define _MSS_WORKAROUNDS_DP16_H_

#include <fapi2.H>

namespace mss
{

namespace workarounds
{

namespace dp16
{

///
/// @brief DQS polarity workaround
/// For Monza DDR port 2, one pair of DQS P/N is swapped polarity.  Not in DDR port 6
/// @param[in] i_target the fapi2 target of the port
/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if ok
/// @note This function is called during the phy scom init procedure, after the initfile is
/// processed. It is specific to the Monza module, but can be called for all modules as it
/// will enforce its requirements internally
///
fapi2::ReturnCode dqs_polarity( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target );

} // close namespace dp16
} // close namespace workarounds
} // close namespace mss

#endif
<commit_msg>Add SEQ timing parameters, DP16 RD Diag config 5 inits<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/memory/lib/workarounds/dp16_workarounds.H $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2016,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

///
/// @file workarounds/dp16.H
/// @brief Workarounds for the DP16 logic blocks
/// Workarounds are very deivce specific, so there is no attempt to generalize
/// this code in any way.
///
// *HWP HWP Owner: Brian Silver <bsilver@us.ibm.com>
// *HWP HWP Backup: Steven Glancy <sglancy@usi.ibm.com>
// *HWP Team: Memory
// *HWP Level: 2
// *HWP Consumed by: FSP:HB

#ifndef _MSS_WORKAROUNDS_DP16_H_
#define _MSS_WORKAROUNDS_DP16_H_

#include <fapi2.H>

namespace mss
{

namespace workarounds
{

namespace dp16
{

///
/// @brief DQS polarity workaround
/// For Monza DDR port 2, one pair of DQS P/N is swapped polarity.  Not in DDR port 6
/// @param[in] i_target the fapi2 target of the port
/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if ok
/// @note This function is called during the phy scom init procedure, after the initfile is
/// processed. It is specific to the Monza module, but can be called for all modules as it
/// will enforce its requirements internally
///
fapi2::ReturnCode dqs_polarity( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target );

///
/// @brief DP16 Read Diagnostic Configuration 5 work around
/// Not in the Model 67 spydef, so we scom them. Should be removed when they are
/// added to the spydef.
/// @param[in] i_target the fapi2 target of the port
/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if ok
///
fapi2::ReturnCode rd_dia_config5( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target );

} // close namespace dp16
} // close namespace workarounds
} // close namespace mss

#endif
<|endoftext|>


<commit_before>/***************************************************************************
 *   Copyright (C) 2006 by Till Adam <adam@kde.org>                        *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU Library General Public License as       *
 *   published by the Free Software Foundation; either version 2 of the    *
 *   License, or (at your option) any later version.                       *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this program; if not, write to the                 *
 *   Free Software Foundation, Inc.,                                       *
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.             *
 ***************************************************************************/
#include "akonadiconnection.h"

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

#include "storage/datastore.h"
#include "handler.h"
#include "response.h"
#include "tracer.h"

#include "libs/imapparser_p.h"
#include "imapstreamparser.h"
#include "shared/akdebug.h"
#include "shared/akcrash.h"

#include <assert.h>

using namespace Akonadi;

AkonadiConnection::AkonadiConnection( quintptr socketDescriptor, QObject *parent )
    : QThread(parent)
    , m_socketDescriptor(socketDescriptor)
    , m_socket( 0 )
    , m_currentHandler( 0 )
    , m_connectionState( NonAuthenticated )
    , m_backend( 0 )
    , m_selectedConnection( 0 )
    , m_parser( 0 )
    , m_streamParser( 0 )
{
    m_identifier.sprintf( "%p", static_cast<void*>( this ) );
    Tracer::self()->beginConnection( m_identifier, QString() );
    m_parser = new ImapParser;
}

DataStore * Akonadi::AkonadiConnection::storageBackend()
{
    if ( !m_backend )
      m_backend = DataStore::self();
    return m_backend;
}

AkonadiConnection::~AkonadiConnection()
{
    Tracer::self()->endConnection( m_identifier, QString() );

    delete m_parser;
}

void AkonadiConnection::run()
{
    m_socket = new QLocalSocket();

    if ( !m_socket->setSocketDescriptor( m_socketDescriptor ) ) {
        qWarning() << "AkonadiConnection(" << m_identifier
                 << ")::run: failed to set socket descriptor: "
                 << m_socket->error() << "(" << m_socket->errorString() << ")";
        delete m_socket;
        m_socket = 0;
        return;
    }

    /* Start a local event loop and start processing incoming data. Whenever
     * a full command has been read, it is delegated to the responsible
     * handler and processed by that. If that command needs to do something
     * asynchronous such as ask the db for data, it returns and the input
     * queue can continue to be processed. Whenever there is something to
     * be sent back to the user it is queued in the form of a Response object.
     * All this is meant to make it possible to process large incoming or
     * outgoing data transfers in a streaming manner, without having to
     * hold them in memory 'en gros'. */

    connect( m_socket, SIGNAL( readyRead() ),
             this, SLOT( slotNewData() ), Qt::DirectConnection );
    connect( m_socket, SIGNAL( disconnected() ),
             this, SLOT( slotDisconnected() ), Qt::DirectConnection );

    writeOut( "* OK Akonadi Almost IMAP Server [PROTOCOL 12]");

    m_streamParser = new ImapStreamParser( m_socket );
    exec();
    delete m_socket;
    m_socket = 0;
    delete m_streamParser;
    m_streamParser = 0;
}

void AkonadiConnection::slotDisconnected()
{
    quit();
}

void AkonadiConnection::slotNewData()
{
  while ( m_socket->bytesAvailable() > 0 || !m_streamParser->readRemainingData().isEmpty()) {
    try {
      const QByteArray tag = m_streamParser->readString();
      const QByteArray command = m_streamParser->readString();
      Tracer::self()->connectionInput( m_identifier, QString::fromUtf8( tag + " " + command + " " + m_streamParser->readRemainingData() ) );
      m_currentHandler = findHandlerForCommand( command );
      assert( m_currentHandler );
      connect( m_currentHandler, SIGNAL( responseAvailable( const Response & ) ),
              this, SLOT( slotResponseAvailable( const Response & ) ), Qt::DirectConnection );
      connect( m_currentHandler, SIGNAL( connectionStateChange( ConnectionState ) ),
              this, SLOT( slotConnectionStateChange( ConnectionState ) ),
               Qt::DirectConnection );
      m_currentHandler->setTag( tag );
      m_currentHandler->setStreamParser( m_streamParser );
      if ( !m_currentHandler->parseStream() ) {
        m_streamParser->readUntilCommandEnd(); //just eat the ending newline
      }
    } catch ( const Akonadi::HandlerException &e ) {
      m_currentHandler->failureResponse( e.what() );
      m_streamParser->readUntilCommandEnd(); //just eat the ending newline
    } catch ( const Akonadi::Exception &e ) {
      m_currentHandler->failureResponse( QString::fromLatin1( e.type() )
          + QLatin1String( ": " ) + QString::fromLatin1( e.what()  ) );
      m_streamParser->readUntilCommandEnd(); //just eat the ending newline
    } catch ( ... ) {
      akError() << "Unknown exception caught: " << akBacktrace();
      m_currentHandler->failureResponse( "Unknown exception caught" );
      m_streamParser->readUntilCommandEnd(); //just eat the ending newline
    }
    delete m_currentHandler;
    m_currentHandler = 0;

    if (m_streamParser->readRemainingData().startsWith('\n') || m_streamParser->readRemainingData().startsWith("\r\n"))
      m_streamParser->readUntilCommandEnd(); //just eat the ending newline
  }
}

void AkonadiConnection::writeOut( const QByteArray &data )
{
    QByteArray block = data + "\r\n";
    m_socket->write(block);
    m_socket->waitForBytesWritten();

    Tracer::self()->connectionOutput( m_identifier, QString::fromUtf8( block ) );
}

Handler * AkonadiConnection::findHandlerForCommand( const QByteArray & command )
{
    Handler * handler = Handler::findHandlerForCommandAlwaysAllowed( command );
    if ( handler ) return handler;

    switch ( m_connectionState ) {
        case NonAuthenticated:
            handler =  Handler::findHandlerForCommandNonAuthenticated( command );
            break;
        case Authenticated:
            handler =  Handler::findHandlerForCommandAuthenticated( command, m_streamParser );
            break;
        case Selected:
            break;
        case LoggingOut:
            break;
    }
    // we didn't have a handler for this, let the default one do its thing
    if ( !handler ) handler = new UnknownCommandHandler( command );
    handler->setConnection( this );
    return handler;
}

void AkonadiConnection::slotResponseAvailable( const Response& response )
{
    // FIXME handle reentrancy in the presence of continuation. Something like:
    // "if continuation pending, queue responses, once continuation is done, replay them"
    writeOut( response.asString() );
}

void AkonadiConnection::slotConnectionStateChange( ConnectionState state )
{
    if ( state == m_connectionState ) return;
    m_connectionState = state;
    switch ( m_connectionState ) {
        case NonAuthenticated:
            assert( 0 ); // can't happen, it's only the initial state, we can't go back to it
            break;
        case Authenticated:
            break;
        case Selected:
            break;
        case LoggingOut:
            m_socket->disconnectFromServer();
            break;
    }
}

qint64 Akonadi::AkonadiConnection::selectedCollectionId( ) const
{
    return m_selectedConnection;
}

void Akonadi::AkonadiConnection::setSelectedCollection( qint64 collection )
{
    m_selectedConnection = collection;
}

const Collection Akonadi::AkonadiConnection::selectedCollection()
{
  return Collection::retrieveById( selectedCollectionId() );
}

void Akonadi::AkonadiConnection::addStatusMessage( const QByteArray& msg )
{
    m_statusMessageQueue.append( msg );
}

void Akonadi::AkonadiConnection::flushStatusMessageQueue()
{
    for ( int i = 0; i < m_statusMessageQueue.count(); ++i ) {
      Response response;
      response.setUntagged();
      response.setString( m_statusMessageQueue[ i ] );

      slotResponseAvailable( response );
    }

    m_statusMessageQueue.clear();
}

void AkonadiConnection::setSessionId(const QByteArray &id)
{
  m_sessionId = id;
  storageBackend()->setSessionId( id );
  storageBackend()->notificationCollector()->setSessionId( id );
}

QByteArray AkonadiConnection::sessionId() const
{
  return m_sessionId;
}

Resource Akonadi::AkonadiConnection::resourceContext() const
{
  return m_resourceContext;
}

void AkonadiConnection::setResourceContext(const Resource& res)
{
  m_resourceContext = res;
}

bool AkonadiConnection::isOwnerResource(const PimItem& item) const
{
  if ( resourceContext().isValid() )
    return true;
  // fallback for older resources
  if ( sessionId() == item.collection().resource().name().toUtf8() )
    return true;
  return false;
}

#include "akonadiconnection.moc"
<commit_msg>Deal with stray newlines caused by zero-sized literals. The real fix for this would be on the client side, but being more robust against received garbage can't hurt either. This fixes most of the unknown command/empty command errors for me, as well as most of the unit tests.<commit_after>/***************************************************************************
 *   Copyright (C) 2006 by Till Adam <adam@kde.org>                        *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU Library General Public License as       *
 *   published by the Free Software Foundation; either version 2 of the    *
 *   License, or (at your option) any later version.                       *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this program; if not, write to the                 *
 *   Free Software Foundation, Inc.,                                       *
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.             *
 ***************************************************************************/
#include "akonadiconnection.h"

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

#include "storage/datastore.h"
#include "handler.h"
#include "response.h"
#include "tracer.h"

#include "libs/imapparser_p.h"
#include "imapstreamparser.h"
#include "shared/akdebug.h"
#include "shared/akcrash.h"

#include <assert.h>

using namespace Akonadi;

AkonadiConnection::AkonadiConnection( quintptr socketDescriptor, QObject *parent )
    : QThread(parent)
    , m_socketDescriptor(socketDescriptor)
    , m_socket( 0 )
    , m_currentHandler( 0 )
    , m_connectionState( NonAuthenticated )
    , m_backend( 0 )
    , m_selectedConnection( 0 )
    , m_parser( 0 )
    , m_streamParser( 0 )
{
    m_identifier.sprintf( "%p", static_cast<void*>( this ) );
    Tracer::self()->beginConnection( m_identifier, QString() );
    m_parser = new ImapParser;
}

DataStore * Akonadi::AkonadiConnection::storageBackend()
{
    if ( !m_backend )
      m_backend = DataStore::self();
    return m_backend;
}

AkonadiConnection::~AkonadiConnection()
{
    Tracer::self()->endConnection( m_identifier, QString() );

    delete m_parser;
}

void AkonadiConnection::run()
{
    m_socket = new QLocalSocket();

    if ( !m_socket->setSocketDescriptor( m_socketDescriptor ) ) {
        qWarning() << "AkonadiConnection(" << m_identifier
                 << ")::run: failed to set socket descriptor: "
                 << m_socket->error() << "(" << m_socket->errorString() << ")";
        delete m_socket;
        m_socket = 0;
        return;
    }

    /* Start a local event loop and start processing incoming data. Whenever
     * a full command has been read, it is delegated to the responsible
     * handler and processed by that. If that command needs to do something
     * asynchronous such as ask the db for data, it returns and the input
     * queue can continue to be processed. Whenever there is something to
     * be sent back to the user it is queued in the form of a Response object.
     * All this is meant to make it possible to process large incoming or
     * outgoing data transfers in a streaming manner, without having to
     * hold them in memory 'en gros'. */

    connect( m_socket, SIGNAL( readyRead() ),
             this, SLOT( slotNewData() ), Qt::DirectConnection );
    connect( m_socket, SIGNAL( disconnected() ),
             this, SLOT( slotDisconnected() ), Qt::DirectConnection );

    writeOut( "* OK Akonadi Almost IMAP Server [PROTOCOL 12]");

    m_streamParser = new ImapStreamParser( m_socket );
    exec();
    delete m_socket;
    m_socket = 0;
    delete m_streamParser;
    m_streamParser = 0;
}

void AkonadiConnection::slotDisconnected()
{
    quit();
}

void AkonadiConnection::slotNewData()
{
  while ( m_socket->bytesAvailable() > 0 || !m_streamParser->readRemainingData().isEmpty()) {
    try {
      const QByteArray tag = m_streamParser->readString();
      // deal with stray newlines
      if ( tag.isEmpty() && m_streamParser->atCommandEnd() )
        continue;
      const QByteArray command = m_streamParser->readString();
      Tracer::self()->connectionInput( m_identifier, QString::fromUtf8( tag + " " + command + " " + m_streamParser->readRemainingData() ) );
      m_currentHandler = findHandlerForCommand( command );
      assert( m_currentHandler );
      connect( m_currentHandler, SIGNAL( responseAvailable( const Response & ) ),
              this, SLOT( slotResponseAvailable( const Response & ) ), Qt::DirectConnection );
      connect( m_currentHandler, SIGNAL( connectionStateChange( ConnectionState ) ),
              this, SLOT( slotConnectionStateChange( ConnectionState ) ),
               Qt::DirectConnection );
      m_currentHandler->setTag( tag );
      m_currentHandler->setStreamParser( m_streamParser );
      if ( !m_currentHandler->parseStream() ) {
        m_streamParser->readUntilCommandEnd(); //just eat the ending newline
      }
    } catch ( const Akonadi::HandlerException &e ) {
      m_currentHandler->failureResponse( e.what() );
      m_streamParser->readUntilCommandEnd(); //just eat the ending newline
    } catch ( const Akonadi::Exception &e ) {
      m_currentHandler->failureResponse( QString::fromLatin1( e.type() )
          + QLatin1String( ": " ) + QString::fromLatin1( e.what()  ) );
      m_streamParser->readUntilCommandEnd(); //just eat the ending newline
    } catch ( ... ) {
      akError() << "Unknown exception caught: " << akBacktrace();
      m_currentHandler->failureResponse( "Unknown exception caught" );
      m_streamParser->readUntilCommandEnd(); //just eat the ending newline
    }
    delete m_currentHandler;
    m_currentHandler = 0;

    if (m_streamParser->readRemainingData().startsWith('\n') || m_streamParser->readRemainingData().startsWith("\r\n"))
      m_streamParser->readUntilCommandEnd(); //just eat the ending newline
  }
}

void AkonadiConnection::writeOut( const QByteArray &data )
{
    QByteArray block = data + "\r\n";
    m_socket->write(block);
    m_socket->waitForBytesWritten();

    Tracer::self()->connectionOutput( m_identifier, QString::fromUtf8( block ) );
}

Handler * AkonadiConnection::findHandlerForCommand( const QByteArray & command )
{
    Handler * handler = Handler::findHandlerForCommandAlwaysAllowed( command );
    if ( handler ) return handler;

    switch ( m_connectionState ) {
        case NonAuthenticated:
            handler =  Handler::findHandlerForCommandNonAuthenticated( command );
            break;
        case Authenticated:
            handler =  Handler::findHandlerForCommandAuthenticated( command, m_streamParser );
            break;
        case Selected:
            break;
        case LoggingOut:
            break;
    }
    // we didn't have a handler for this, let the default one do its thing
    if ( !handler ) handler = new UnknownCommandHandler( command );
    handler->setConnection( this );
    return handler;
}

void AkonadiConnection::slotResponseAvailable( const Response& response )
{
    // FIXME handle reentrancy in the presence of continuation. Something like:
    // "if continuation pending, queue responses, once continuation is done, replay them"
    writeOut( response.asString() );
}

void AkonadiConnection::slotConnectionStateChange( ConnectionState state )
{
    if ( state == m_connectionState ) return;
    m_connectionState = state;
    switch ( m_connectionState ) {
        case NonAuthenticated:
            assert( 0 ); // can't happen, it's only the initial state, we can't go back to it
            break;
        case Authenticated:
            break;
        case Selected:
            break;
        case LoggingOut:
            m_socket->disconnectFromServer();
            break;
    }
}

qint64 Akonadi::AkonadiConnection::selectedCollectionId( ) const
{
    return m_selectedConnection;
}

void Akonadi::AkonadiConnection::setSelectedCollection( qint64 collection )
{
    m_selectedConnection = collection;
}

const Collection Akonadi::AkonadiConnection::selectedCollection()
{
  return Collection::retrieveById( selectedCollectionId() );
}

void Akonadi::AkonadiConnection::addStatusMessage( const QByteArray& msg )
{
    m_statusMessageQueue.append( msg );
}

void Akonadi::AkonadiConnection::flushStatusMessageQueue()
{
    for ( int i = 0; i < m_statusMessageQueue.count(); ++i ) {
      Response response;
      response.setUntagged();
      response.setString( m_statusMessageQueue[ i ] );

      slotResponseAvailable( response );
    }

    m_statusMessageQueue.clear();
}

void AkonadiConnection::setSessionId(const QByteArray &id)
{
  m_sessionId = id;
  storageBackend()->setSessionId( id );
  storageBackend()->notificationCollector()->setSessionId( id );
}

QByteArray AkonadiConnection::sessionId() const
{
  return m_sessionId;
}

Resource Akonadi::AkonadiConnection::resourceContext() const
{
  return m_resourceContext;
}

void AkonadiConnection::setResourceContext(const Resource& res)
{
  m_resourceContext = res;
}

bool AkonadiConnection::isOwnerResource(const PimItem& item) const
{
  if ( resourceContext().isValid() )
    return true;
  // fallback for older resources
  if ( sessionId() == item.collection().resource().name().toUtf8() )
    return true;
  return false;
}

#include "akonadiconnection.moc"
<|endoftext|>


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

#include "webrtc/modules/desktop_capture/window_capturer.h"

#include <assert.h>

#include "webrtc/base/scoped_ptr.h"
#include "webrtc/base/checks.h"
#include "webrtc/base/win32.h"
#include "webrtc/modules/desktop_capture/desktop_frame_win.h"
#include "webrtc/modules/desktop_capture/win/window_capture_utils.h"
#include "webrtc/system_wrappers/include/logging.h"

namespace webrtc {

namespace {

BOOL CALLBACK WindowsEnumerationHandler(HWND hwnd, LPARAM param) {
  WindowCapturer::WindowList* list =
      reinterpret_cast<WindowCapturer::WindowList*>(param);

  // Skip windows that are invisible, minimized, have no title, or are owned,
  // unless they have the app window style set.
  int len = GetWindowTextLength(hwnd);
  HWND owner = GetWindow(hwnd, GW_OWNER);
  LONG exstyle = GetWindowLong(hwnd, GWL_EXSTYLE);
  if (len == 0 || IsIconic(hwnd) || !IsWindowVisible(hwnd) ||
      (owner && !(exstyle & WS_EX_APPWINDOW))) {
    return TRUE;
  }

  // Skip the Program Manager window and the Start button.
  const size_t kClassLength = 256;
  WCHAR class_name[kClassLength];
  const int class_name_length = GetClassName(hwnd, class_name, kClassLength);
  RTC_DCHECK(class_name_length)
      << "Error retrieving the application's class name";

  // Skip Program Manager window and the Start button. This is the same logic
  // that's used in Win32WindowPicker in libjingle. Consider filtering other
  // windows as well (e.g. toolbars).
  if (wcscmp(class_name, L"Progman") == 0 || wcscmp(class_name, L"Button") == 0)
    return TRUE;

  // Windows 8 introduced a "Modern App" identified by their class name being
  // either ApplicationFrameWindow or windows.UI.Core.coreWindow. The
  // associated windows cannot be captured, so we skip them.
  // http://crbug.com/526883.
  if (rtc::IsWindows8OrLater() &&
      (wcscmp(class_name, L"ApplicationFrameWindow") == 0 ||
       wcscmp(class_name, L"Windows.UI.Core.CoreWindow") == 0)) {
    return TRUE;
  }

  WindowCapturer::Window window;
  window.id = reinterpret_cast<WindowCapturer::WindowId>(hwnd);

  const size_t kTitleLength = 500;
  WCHAR window_title[kTitleLength];
  // Truncate the title if it's longer than kTitleLength.
  GetWindowText(hwnd, window_title, kTitleLength);
  window.title = rtc::ToUtf8(window_title);

  // Skip windows when we failed to convert the title or it is empty.
  if (window.title.empty())
    return TRUE;

  list->push_back(window);

  return TRUE;
}

class WindowCapturerWin : public WindowCapturer {
 public:
  WindowCapturerWin();
  virtual ~WindowCapturerWin();

  // WindowCapturer interface.
  bool GetWindowList(WindowList* windows) override;
  bool SelectWindow(WindowId id) override;
  bool BringSelectedWindowToFront() override;

  // DesktopCapturer interface.
  void Start(Callback* callback) override;
  void Capture(const DesktopRegion& region) override;

 private:
  Callback* callback_;

  // HWND and HDC for the currently selected window or NULL if window is not
  // selected.
  HWND window_;

  DesktopSize previous_size_;

  AeroChecker aero_checker_;

  RTC_DISALLOW_COPY_AND_ASSIGN(WindowCapturerWin);
};

WindowCapturerWin::WindowCapturerWin()
    : callback_(NULL),
      window_(NULL) {
}

WindowCapturerWin::~WindowCapturerWin() {
}

bool WindowCapturerWin::GetWindowList(WindowList* windows) {
  WindowList result;
  LPARAM param = reinterpret_cast<LPARAM>(&result);
  if (!EnumWindows(&WindowsEnumerationHandler, param))
    return false;
  windows->swap(result);
  return true;
}

bool WindowCapturerWin::SelectWindow(WindowId id) {
  HWND window = reinterpret_cast<HWND>(id);
  if (!IsWindow(window) || !IsWindowVisible(window) || IsIconic(window))
    return false;
  window_ = window;
  previous_size_.set(0, 0);
  return true;
}

bool WindowCapturerWin::BringSelectedWindowToFront() {
  if (!window_)
    return false;

  if (!IsWindow(window_) || !IsWindowVisible(window_) || IsIconic(window_))
    return false;

  return SetForegroundWindow(window_) != 0;
}

void WindowCapturerWin::Start(Callback* callback) {
  assert(!callback_);
  assert(callback);

  callback_ = callback;
}

void WindowCapturerWin::Capture(const DesktopRegion& region) {
  if (!window_) {
    LOG(LS_ERROR) << "Window hasn't been selected: " << GetLastError();
    callback_->OnCaptureCompleted(NULL);
    return;
  }

  // Stop capturing if the window has been closed.
  if (!IsWindow(window_)) {
    callback_->OnCaptureCompleted(NULL);
    return;
  }

  // Return a 1x1 black frame if the window is minimized or invisible, to match
  // behavior on mace. Window can be temporarily invisible during the
  // transition of full screen mode on/off.
  if (IsIconic(window_) || !IsWindowVisible(window_)) {
    BasicDesktopFrame* frame = new BasicDesktopFrame(DesktopSize(1, 1));
    memset(frame->data(), 0, frame->stride() * frame->size().height());

    previous_size_ = frame->size();
    callback_->OnCaptureCompleted(frame);
    return;
  }

  DesktopRect original_rect;
  DesktopRect cropped_rect;
  if (!GetCroppedWindowRect(window_, &cropped_rect, &original_rect)) {
    LOG(LS_WARNING) << "Failed to get window info: " << GetLastError();
    callback_->OnCaptureCompleted(NULL);
    return;
  }

  HDC window_dc = GetWindowDC(window_);
  if (!window_dc) {
    LOG(LS_WARNING) << "Failed to get window DC: " << GetLastError();
    callback_->OnCaptureCompleted(NULL);
    return;
  }

  rtc::scoped_ptr<DesktopFrameWin> frame(
      DesktopFrameWin::Create(cropped_rect.size(), NULL, window_dc));
  if (!frame.get()) {
    ReleaseDC(window_, window_dc);
    callback_->OnCaptureCompleted(NULL);
    return;
  }

  HDC mem_dc = CreateCompatibleDC(window_dc);
  HGDIOBJ previous_object = SelectObject(mem_dc, frame->bitmap());
  BOOL result = FALSE;

  // When desktop composition (Aero) is enabled each window is rendered to a
  // private buffer allowing BitBlt() to get the window content even if the
  // window is occluded. PrintWindow() is slower but lets rendering the window
  // contents to an off-screen device context when Aero is not available.
  // PrintWindow() is not supported by some applications.
  //
  // If Aero is enabled, we prefer BitBlt() because it's faster and avoids
  // window flickering. Otherwise, we prefer PrintWindow() because BitBlt() may
  // render occluding windows on top of the desired window.
  //
  // When composition is enabled the DC returned by GetWindowDC() doesn't always
  // have window frame rendered correctly. Windows renders it only once and then
  // caches the result between captures. We hack it around by calling
  // PrintWindow() whenever window size changes, including the first time of
  // capturing - it somehow affects what we get from BitBlt() on the subsequent
  // captures.

  if (!aero_checker_.IsAeroEnabled() || !previous_size_.equals(frame->size())) {
    result = PrintWindow(window_, mem_dc, 0);
  }

  // Aero is enabled or PrintWindow() failed, use BitBlt.
  if (!result) {
    result = BitBlt(mem_dc, 0, 0, frame->size().width(), frame->size().height(),
                    window_dc,
                    cropped_rect.left() - original_rect.left(),
                    cropped_rect.top() - original_rect.top(),
                    SRCCOPY);
  }

  SelectObject(mem_dc, previous_object);
  DeleteDC(mem_dc);
  ReleaseDC(window_, window_dc);

  previous_size_ = frame->size();

  frame->mutable_updated_region()->SetRect(
      DesktopRect::MakeSize(frame->size()));

  if (!result) {
    LOG(LS_ERROR) << "Both PrintWindow() and BitBlt() failed.";
    frame.reset();
  }

  callback_->OnCaptureCompleted(frame.release());
}

}  // namespace

// static
WindowCapturer* WindowCapturer::Create(const DesktopCaptureOptions& options) {
  return new WindowCapturerWin();
}

}  // namespace webrtc
<commit_msg>Screen was flickering when the picker for desktop medias showed up in Windows platform. Keeping track of window size for each window so that BitBlt() instead of PrintWindow() will be called for windows with unchanged sizes.<commit_after>/*
 *  Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "webrtc/modules/desktop_capture/window_capturer.h"

#include <assert.h>

#include "webrtc/base/scoped_ptr.h"
#include "webrtc/base/checks.h"
#include "webrtc/base/win32.h"
#include "webrtc/modules/desktop_capture/desktop_frame_win.h"
#include "webrtc/modules/desktop_capture/win/window_capture_utils.h"
#include "webrtc/system_wrappers/include/logging.h"

namespace webrtc {

namespace {

BOOL CALLBACK WindowsEnumerationHandler(HWND hwnd, LPARAM param) {
  WindowCapturer::WindowList* list =
      reinterpret_cast<WindowCapturer::WindowList*>(param);

  // Skip windows that are invisible, minimized, have no title, or are owned,
  // unless they have the app window style set.
  int len = GetWindowTextLength(hwnd);
  HWND owner = GetWindow(hwnd, GW_OWNER);
  LONG exstyle = GetWindowLong(hwnd, GWL_EXSTYLE);
  if (len == 0 || IsIconic(hwnd) || !IsWindowVisible(hwnd) ||
      (owner && !(exstyle & WS_EX_APPWINDOW))) {
    return TRUE;
  }

  // Skip the Program Manager window and the Start button.
  const size_t kClassLength = 256;
  WCHAR class_name[kClassLength];
  const int class_name_length = GetClassName(hwnd, class_name, kClassLength);
  RTC_DCHECK(class_name_length)
      << "Error retrieving the application's class name";

  // Skip Program Manager window and the Start button. This is the same logic
  // that's used in Win32WindowPicker in libjingle. Consider filtering other
  // windows as well (e.g. toolbars).
  if (wcscmp(class_name, L"Progman") == 0 || wcscmp(class_name, L"Button") == 0)
    return TRUE;

  // Windows 8 introduced a "Modern App" identified by their class name being
  // either ApplicationFrameWindow or windows.UI.Core.coreWindow. The
  // associated windows cannot be captured, so we skip them.
  // http://crbug.com/526883.
  if (rtc::IsWindows8OrLater() &&
      (wcscmp(class_name, L"ApplicationFrameWindow") == 0 ||
       wcscmp(class_name, L"Windows.UI.Core.CoreWindow") == 0)) {
    return TRUE;
  }

  WindowCapturer::Window window;
  window.id = reinterpret_cast<WindowCapturer::WindowId>(hwnd);

  const size_t kTitleLength = 500;
  WCHAR window_title[kTitleLength];
  // Truncate the title if it's longer than kTitleLength.
  GetWindowText(hwnd, window_title, kTitleLength);
  window.title = rtc::ToUtf8(window_title);

  // Skip windows when we failed to convert the title or it is empty.
  if (window.title.empty())
    return TRUE;

  list->push_back(window);

  return TRUE;
}

class WindowCapturerWin : public WindowCapturer {
 public:
  WindowCapturerWin();
  virtual ~WindowCapturerWin();

  // WindowCapturer interface.
  bool GetWindowList(WindowList* windows) override;
  bool SelectWindow(WindowId id) override;
  bool BringSelectedWindowToFront() override;

  // DesktopCapturer interface.
  void Start(Callback* callback) override;
  void Capture(const DesktopRegion& region) override;

 private:
  Callback* callback_;

  // HWND and HDC for the currently selected window or NULL if window is not
  // selected.
  HWND window_;

  DesktopSize previous_size_;

  AeroChecker aero_checker_;

  // This map is used to avoid flickering for the case when SelectWindow() calls
  // are interleaved with Capture() calls.
  std::map<HWND, DesktopSize> window_size_map_;

  RTC_DISALLOW_COPY_AND_ASSIGN(WindowCapturerWin);
};

WindowCapturerWin::WindowCapturerWin()
    : callback_(NULL),
      window_(NULL) {
}

WindowCapturerWin::~WindowCapturerWin() {
}

bool WindowCapturerWin::GetWindowList(WindowList* windows) {
  WindowList result;
  LPARAM param = reinterpret_cast<LPARAM>(&result);
  if (!EnumWindows(&WindowsEnumerationHandler, param))
    return false;
  windows->swap(result);

  std::map<HWND, DesktopSize> new_map;
  for (const auto& item : *windows) {
    HWND hwnd = reinterpret_cast<HWND>(item.id);
    new_map[hwnd] = window_size_map_[hwnd];
  }
  window_size_map_.swap(new_map);

  return true;
}

bool WindowCapturerWin::SelectWindow(WindowId id) {
  HWND window = reinterpret_cast<HWND>(id);
  if (!IsWindow(window) || !IsWindowVisible(window) || IsIconic(window))
    return false;
  window_ = window;
  // When a window is not in the map, window_size_map_[window] will create an
  // item with DesktopSize (0, 0).
  previous_size_ = window_size_map_[window];
  return true;
}

bool WindowCapturerWin::BringSelectedWindowToFront() {
  if (!window_)
    return false;

  if (!IsWindow(window_) || !IsWindowVisible(window_) || IsIconic(window_))
    return false;

  return SetForegroundWindow(window_) != 0;
}

void WindowCapturerWin::Start(Callback* callback) {
  assert(!callback_);
  assert(callback);

  callback_ = callback;
}

void WindowCapturerWin::Capture(const DesktopRegion& region) {
  if (!window_) {
    LOG(LS_ERROR) << "Window hasn't been selected: " << GetLastError();
    callback_->OnCaptureCompleted(NULL);
    return;
  }

  // Stop capturing if the window has been closed.
  if (!IsWindow(window_)) {
    callback_->OnCaptureCompleted(NULL);
    return;
  }

  // Return a 1x1 black frame if the window is minimized or invisible, to match
  // behavior on mace. Window can be temporarily invisible during the
  // transition of full screen mode on/off.
  if (IsIconic(window_) || !IsWindowVisible(window_)) {
    BasicDesktopFrame* frame = new BasicDesktopFrame(DesktopSize(1, 1));
    memset(frame->data(), 0, frame->stride() * frame->size().height());

    previous_size_ = frame->size();
    window_size_map_[window_] = previous_size_;
    callback_->OnCaptureCompleted(frame);
    return;
  }

  DesktopRect original_rect;
  DesktopRect cropped_rect;
  if (!GetCroppedWindowRect(window_, &cropped_rect, &original_rect)) {
    LOG(LS_WARNING) << "Failed to get window info: " << GetLastError();
    callback_->OnCaptureCompleted(NULL);
    return;
  }

  HDC window_dc = GetWindowDC(window_);
  if (!window_dc) {
    LOG(LS_WARNING) << "Failed to get window DC: " << GetLastError();
    callback_->OnCaptureCompleted(NULL);
    return;
  }

  rtc::scoped_ptr<DesktopFrameWin> frame(
      DesktopFrameWin::Create(cropped_rect.size(), NULL, window_dc));
  if (!frame.get()) {
    ReleaseDC(window_, window_dc);
    callback_->OnCaptureCompleted(NULL);
    return;
  }

  HDC mem_dc = CreateCompatibleDC(window_dc);
  HGDIOBJ previous_object = SelectObject(mem_dc, frame->bitmap());
  BOOL result = FALSE;

  // When desktop composition (Aero) is enabled each window is rendered to a
  // private buffer allowing BitBlt() to get the window content even if the
  // window is occluded. PrintWindow() is slower but lets rendering the window
  // contents to an off-screen device context when Aero is not available.
  // PrintWindow() is not supported by some applications.
  //
  // If Aero is enabled, we prefer BitBlt() because it's faster and avoids
  // window flickering. Otherwise, we prefer PrintWindow() because BitBlt() may
  // render occluding windows on top of the desired window.
  //
  // When composition is enabled the DC returned by GetWindowDC() doesn't always
  // have window frame rendered correctly. Windows renders it only once and then
  // caches the result between captures. We hack it around by calling
  // PrintWindow() whenever window size changes, including the first time of
  // capturing - it somehow affects what we get from BitBlt() on the subsequent
  // captures.

  if (!aero_checker_.IsAeroEnabled() || !previous_size_.equals(frame->size())) {
    result = PrintWindow(window_, mem_dc, 0);
  }

  // Aero is enabled or PrintWindow() failed, use BitBlt.
  if (!result) {
    result = BitBlt(mem_dc, 0, 0, frame->size().width(), frame->size().height(),
                    window_dc,
                    cropped_rect.left() - original_rect.left(),
                    cropped_rect.top() - original_rect.top(),
                    SRCCOPY);
  }

  SelectObject(mem_dc, previous_object);
  DeleteDC(mem_dc);
  ReleaseDC(window_, window_dc);

  previous_size_ = frame->size();
  window_size_map_[window_] = previous_size_;

  frame->mutable_updated_region()->SetRect(
      DesktopRect::MakeSize(frame->size()));

  if (!result) {
    LOG(LS_ERROR) << "Both PrintWindow() and BitBlt() failed.";
    frame.reset();
  }

  callback_->OnCaptureCompleted(frame.release());
}

}  // namespace

// static
WindowCapturer* WindowCapturer::Create(const DesktopCaptureOptions& options) {
  return new WindowCapturerWin();
}

}  // namespace webrtc
<|endoftext|>