//
//
// Copyright 2002 Rob Tougher <robt@robtougher.com>
//
// This file is part of xmlrpc.
//
// xmlrpc is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// xmlrpc 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 General Public License
// along with xmlrpc; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//


// definition of the thread class

#ifndef _threads_thread_class_
#define _threads_thread_class_

#include <pthread.h>
#include "thread_exceptions.hpp"



namespace threads
{

  //
  // The thread class creates a pthread, and gives its
  // static member "thread_func" as the thread
  // function to be called.
  //
  template<typename _F>
  class thread
  {
  public:

    //
    // constructor: create a thread with
    // pthread_create(). Pass our 'this' pointer
    // as the thread function argument.
    //
    thread ( _F f ) : m_functor ( f ), m_finished ( false )
    {
      pthread_attr_t attr;
      int argument = 0;

      int return_value = pthread_create ( &m_thread,
					  ( pthread_attr_t * ) 0,
					  &thread_func,
					  ( void * ) this );

      if ( return_value != 0 )
	{
	  throw thread_exception ( "Could not create thread" );
	}
    }


    //
    // Join halts the calling thread until m_thread
    // has finished.
    //
    void join() const
    {
      pthread_join ( m_thread, 0 );
    }


    //
    // thread_func is called by "pthread_create". We
    // cast the param to a thread object, and call
    // the operator() member of m_functor.
    //
    static void * thread_func ( void * param )
    {
      thread* t = static_cast<thread*>(param);
      t->m_functor();
      t->m_finished = true;
      return 0;
    }

    ~thread()
    {}

    bool is_finished() const { return m_finished; }

  private:

    _F m_functor;
    pthread_t m_thread;

    bool m_finished;

    //
    // don't allow these
    //
    thread ( const thread& );
    void operator = ( const thread& );

  };

}


#endif