////////////////////////////////////////////////////////////
//
//     	Declaration of classes
//	AThreadAttributes, AThread, AAsyncStep, AThreadControl
//
//      Copyright 2001 Alexander Liss
//
////////////////////////////////////////////////////////////

#ifndef __THREAD_H__
#define __THREAD_H__


#include "AMutex.h"
#include "ACondition.h"
            

// for a thread we need two objects 
// one of a type AThread, another of a type AThreadControl
// it is best to allocate them in 
// a global space, a heap or a stack of main()


class AThreadControl;


	// AThreadAttributes

class AThreadAttributes
{
friend class AThreadControl;
public:
	
	int status;
	
	// for POSIX kernel threads:
	// inherit shedule, system scope, stack size 64K, automatically allocates stack
	AThreadAttributes();
		
	~AThreadAttributes();
		
 	// for POSIX kernel threads: see sched.h, rtsched(2), 
 	// policy indexes are different for kernel threads and old dce threads
      	int set_schedule_policy(int z); 
      	
      	// for POSIX kernel threads: 
      	// works only with automatically allocated stack address (default)
      	// zero guard size - no guarding
      	// default value is PAGESIZE (rounds to a multiple of PAGESIZE)
      	int set_guard_size(int z); 
      	
      	// for POSIX kernel threads minimal size is PTHREAD_STACK_MIN
      	int set_stack_size(int z);
      	
      	int set_priority(int z); 
      	
      	int set_detached();     	
      	
      		      	        	  
      	int set_process_scope(); 
  	       	   
private:

	pthread_attr_t attributes;
			 	
};

	// in-thread processing

        // AThread

// base class; 
// derived class supplies procedures and data (!) for a thread;
// if the same derived class is used to create different threads,
// then threads share procedures (!), but do not share data
class AThread 
{
friend class AThreadControl;
public:

	AThread():loop_sleep(0),destruct(false){}
	virtual ~AThread(){}

	// wait on thread's mutex-condition pair, to respond to wake_up() and selfdestruct()
	// used when there is no internal waits in loop() function
	void sleep_in_loop(unsigned milliseconds){loop_sleep=milliseconds;}
	// one step of a loop between waits
	void wake_up(){thread_condition.signal();} 
	void selfdestruct();

protected:

	// in addition to the constructor, called inside the thread function
	// Note - default implementation is non-trivial, 
	// at override call AThread::startup(); in the beginning
	virtual int startup();

	virtual int loop(bool& continue_loop)
        {continue_loop=false; return 0;}

	// cleanup what startup() had allocated or opened
	virtual int cleanup(){return 0;}

        unsigned loop_sleep;
        bool destruct;
        AMutex thread_mutex;
        ACondition thread_condition;
};


        // AAsyncStep

class AAsyncStep:public AThread
{
AAsyncStep(const AAsyncStep&);
AAsyncStep& operator=(const AAsyncStep&);
public:
	AAsyncStep(){}
	int step(){wake_up();return 0;}
protected:
	virtual int respond()=0;
private:
	int loop(bool& continue_loop);
};

	
	// thread management

        // AThreadControl

class AThreadControl 
{
friend int AWait(AThreadControl&);
AThreadControl(const AThreadControl&);
AThreadControl& operator=(const AThreadControl&);
public:
 
        // thread return values
        enum
        {
                destructed=0,
                failed_startup=1,
                bad_loop=2,
                failed_cleanup=3
        };
        
	AThreadControl():thread_object(0){}
	~AThreadControl(){}
	

	// launch the thread
	int launch( AThread& thread, AThreadAttributes& atributes);

	// launch the thread with default attributes
	int launch( AThread& thread);
	
	
	// following functions can be called only after launch():
	
	int get_priority(int& priority);
	// a calling process
	//  should have appropriate privileges to call this:
	int change_priority(int priority);
	int detach();
		
 
	int suspend(); 	// suspend the thread
	int resume();	// continue the thread
	int terminate();// cancel the thread
	
protected:

        AThread * thread_object;  
    	pthread_t handle;
        static void* thread_procedure(void *thread);
};




#endif