//------------------------------------------------------------------------------
//	Copyright (C) 2009, 2010 Humboldt-Universitaet zu Berlin
//
//	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) any later version.
//
//	This library is distributed in the hope that it will be useful,
//	but WITHOUT ANY WARRANTY; without even the implied warranty of
//	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//	Lesser General Public License for more details.
//
//	You should have received a copy of the GNU Lesser General Public
//	License along with this library; if not, write to the Free Software
//	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//------------------------------------------------------------------------------

/**
 * @file ucFiber.h
 * @author Klaus Ahrens
 * @date created at 2009/03/16
 * @brief Declaration of class ucFiber
 * @sa ucFiber.cpp
 * @since 3.0
 */

#ifndef ODEMX_UCFIBER_INCLUDED
#define ODEMX_UCFIBER_INCLUDED

#ifndef _WIN32

#ifndef _XOPEN_SOURCE
#define _XOPEN_SOURCE 520
#endif

// The value SIGSTKSZ is a system default specifying the number of bytes that
// would be used to cover the usual case when manually allocating an alternate
// stack area
// defined in signal.h
#include <signal.h>

// this is too small an area on a 64 bit system (using 32k fixed size)
//#ifdef SIGSTKSZ
//	#define ODEMX_DEFAULT_STACK_SIZE SIGSTKSZ
//#else
	#define ODEMX_DEFAULT_STACK_SIZE (32*1024)
//#endif

// make ucFiber compatible with the Windows API
#define CALLBACK
typedef void VOID;
typedef void* LPVOID;
typedef int PVOID; // looks strange but is OK, because all coroutines
		   // pointers are tunneled as indices into a map !

#include <ucontext.h>
#include <cstdlib>
#include <map>


namespace odemx {
namespace coroutine {

/**
 * @brief Fiber implementation wrapping the POSIX user context in a fiber API
 * @ingroup coroutine
 * @author Klaus Ahrens
 * @since 3.0
 */
class ucFiber {
public:

	ucFiber(void* param);
	ucFiber(std::size_t stacksize, void (*start)(void*), void* param);
	~ucFiber();

	static ucFiber* current;

	static void* ConvertThreadToFiber(void* param);
	static void* GetCurrentFiber();
	static void* CreateFiber(std::size_t stacksize, void (*start)(void*), void* param);
	static void  DeleteFiber(void* fiber);
	static void  SwitchToFiber(void* fiber);

	static void  stackcheck();
	static void* getCoroutine(int nr);

private:
	ucontext_t* uc_;
	void* callStack_;
	enum StackState {mainStack, okStack, noStack} stackState_;
	void* tos;
	static std::map<int, void*> allFibers;
	static int nFibers;
};

#define GLOBAL_WRAPPERS
#ifdef GLOBAL_WRAPPERS

inline void* ConvertThreadToFiber(void* param)
{ return ucFiber::ConvertThreadToFiber(param); }

inline void* GetCurrentFiber()
{ return ucFiber::GetCurrentFiber(); }

inline void* CreateFiber(std::size_t stacksize, void (*start)(void*), void* param)
{ return ucFiber::CreateFiber(stacksize, start, param); }

inline void  DeleteFiber(void* fiber)
{ return ucFiber::DeleteFiber(fiber); }

inline void  SwitchToFiber(void* fiber)
{ return ucFiber::SwitchToFiber(fiber); }

inline void  stackcheck()
{ return ucFiber::stackcheck(); }

#endif /* GLOBAL_WRAPPERS */

#endif /* _WIN32 */

} } // namespace odemx::coroutine

#endif /* ODEMX_UCFIBER_INCLUDED */
