/* -*- mode: c++; c-basic-offset: 4; -*-
 *
 * MICO --- a CORBA implementation
 * Copyright (C) 1997-98 Kay Roemer & Arno Puder
 * 
 * os-thread wrapper
 * Copyright (C) 1999 Andreas Schultz                                 
 * 
 * This library 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 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the Free
 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 * Send comments and/or bug reports to:
 *                mico@informatik.uni-frankfurt.de
 * 
 */


#ifndef __mico_os_thread_h__
#define __mico_os_thread_h__

//
// Define HAVE_THREADS if any type of thread implementations are defined.
// supported "implementations" are:
//
// HAVE_PTHREADS        - POSIX Draft 10 PThreads [Single UNIX Spec V.2 & X/Open Interfaces]
//                        (i.e. HP/UX 11, Linux PThreads (Xavier LeRoy@inria.fr))
// HAVE_DCE_THREADS     - POSIX Draft 4 (DCE) Threads (i.e. HP/UX 10)
// HAVE_WIN_THREADS     - M$ Windows threads or whatever M$ calls them...
// HAVE_SOLARIS_THREADS - SUN Solaris Threads.
// HAVE_OSPACE_THREADS  - Object Space(r) Thread<ToolKit>(tm) via D10/D4/Linux
//                                                                              

#if defined (HAVE_PTHREADS) || defined (HAVE_DCE_THREADS) ||                         \
    defined (HAVE_DCE_THREADS) || defined (HAVE_SOLARIS_THREADS) ||                  \
    defined (HAVE_WIN_THREADS)

    #ifndef HAVE_THREADS
    #define HAVE_THREADS      // def'd as a convenience
    #endif // HAVE_THREADS

#endif // HAVE_*THREADS

#ifdef HAVE_THREADS

#include <mico/mtdebug.h>

/*********************** OS dependant includes **********************/

#if defined(HAVE_PTH_THREADS) && defined(HAVE_PTH_H)
#  include <pth.h>
#endif
#if defined(HAVE_PTHREADS) || defined(HAVE_DCETHREADS)
#  ifdef HAVE_PTHREAD_H
#    include <pthread.h>
#  endif 
#  ifdef HAVE_SEMAPHORE_H
#    include <semaphore.h>
#  endif 
#  ifdef HAVE_SCHED_H
#    include <sched.h>
#  endif 
#endif
#if defined(HAVE_SOLARIS_THREADS)
#  ifdef HAVE_THREAD_H
#    include <thread.h>
#  endif 
#  ifdef HAVE_SYNCH_H
#    include <synch.h>
#  endif 
#  ifdef HAVE_SEMAPHORE_H
#    include <semaphore.h>
#  endif 
#endif

/*********************** thread startup mode ************************/

#define _THR_CREATE_AND_BLOCK
//#define _THR_DEFERED_CREATE

/********************* some debugging stuff *************************/

#ifdef MTDEBUG
#  define THREAD_DEBUG( x ) x
#  define MUTEX_DEBUG( x )  x
#  define SEMA_DEBUG( x )   x
#  define COND_DEBUG( x )   x
#  define RWL_DEBUG( x )    x
#else 
#  define THREAD_DEBUG( x )   
#  define MUTEX_DEBUG( x )
#  define SEMA_DEBUG( x )
#  define COND_DEBUG( x )
#  define RWL_DEBUG( x )
#endif // DEBUG


MICO_NAMESPACE_DECL MICOMT {
#ifdef _WINDOWS
	using namespace MICOMT;
#endif
 
#ifdef HAVE_PTHREADS
#include <mico/os-thread/pthreads.h>
#endif // HAVE_PTHREADS

#ifdef HAVE_DCE_THREADS
#include <mico/os-thread/dcethreads.h>
#endif // HAVE_DCE_THREADS

#ifdef HAVE_PTH_THREADS
#include <mico/os-thread/pththreads.h>
#endif // HAVE_PTH_THREADS

#ifdef HAVE_WIN_THREADS
#error not yet
#endif // HAVE_WIN_THREADS

#ifdef HAVE_SOLARIS_THREADS
#include <mico/os-thread/solaris-threads.h>
#endif // HAVE_SOLARIS_THREADS

/******************************** auto Locks *********************************/

class auto_rdLock {
    rwLock &_l;
public:
    auto_rdLock( rwLock& l): _l(l) { l.rdlock(); };
    ~auto_rdLock() { _l.unlock(); };
};

class auto_wrLock {
    rwLock &_l;
public:
    auto_wrLock( rwLock& l): _l(l) { l.wrlock(); };
    ~auto_wrLock() { _l.unlock(); };
};

template <class T>
class rwLocked: public T, public rwLock {
};

class auto_Lock {
    Mutex &_m;
public:
    auto_Lock( Mutex &m): _m(m) { m.lock(); };
    ~auto_Lock() { _m.unlock(); };
};

template <class T>
class Locked: public T, public Mutex {
};

/********************** state controled referece counting ***********************/

/*
 * Rules:
 * - a activeRef() will only succed if the object is "Active"
 * - activeDeref will wake threads waiting to change the objects state
 *   if the refcnt is 0
 * - a StateChange will only succed after refcnt is 0
 */
class StateRefCnt {
public:
    typedef enum { Init, Active, InitShutdown, Shutdown, Terminated } execState;
protected:
    volatile execState  _current_state;
    volatile execState  _new_state;
    MICO_ULong _activerefs;
    Mutex      _mutex;
    CondVar    _cond;
public:

    StateRefCnt(): _current_state(Init),
		   _new_state(Init),
		   _activerefs(0) {};

    MICO_Boolean activeRef() {
	auto_Lock l(_mutex);

	if ((_current_state != _new_state) && (_current_state != Active)) {
	    return FALSE;
	}
	_activerefs++;
	return TRUE;
    };

    void activeDeref() {
	auto_Lock l(_mutex);

	_activerefs--;
	if ( (_activerefs == 0) && (_new_state != Active) )
	    _cond.broadcast();
    };

    MICO_Boolean StateChange( execState s ) {
	auto_Lock l(_mutex);

	if ( s <= _current_state ) {
	    return FALSE;
	}
	_new_state = s;
	//wait until the state change has become effective
	while (_activerefs != 0) {
	    _cond.wait( _mutex );
	}
	if ( _new_state <= _current_state )
	    return FALSE;

	_current_state = _new_state;
	return TRUE;
    };

    execState State() {
	return _current_state;
    };
    MICO_Boolean initShutdown() {
	auto_Lock l(_mutex);

	if (_new_state != Active ) {
	    return FALSE;
	}
	_current_state = _new_state = InitShutdown;
	return TRUE;
    };
};

};

#else // HAVE_THREADS

MICO_NAMESPACE_DECL MICOMT {
#ifdef _WINDOWS
	using namespace MICOMT;
#endif

class auto_rdLock {
public:
    auto_rdLock( rwLock& l) {};
    ~auto_rdLock() {};
};

class auto_wrLock {
public:
    auto_wrLock( rwLock& l) {};
    ~auto_wrLock() {};
};

template <class T>
class rwLocked: public T, public rwLock {
};

class auto_Lock {
public:
    auto_Lock( Mutex& m) {};
    ~auto_Lock() {};
};

template <class T>
class Locked: public T, public Mutex {
};

#endif // HAVE_THREADS



#endif // __mico_os_thread_h__

