/*
 *  ZThreads, a platform-independant, multithreading and 
 *  synchroniation library
 *
 *  Copyright (C) 2000-2002, Eric Crahen, See LGPL.TXT for details
 *
 *  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
 *
 *  SUNY @ Buffalo, hereby disclaims all copyright interest in the
 *  ZThreads library written by Eric Crahen
 */

#ifndef __ZTTHREAD_H__
#define __ZTTHREAD_H__

#include "zthread/ZThread.h"
#include "zthread/FastThreadLocal.h"

namespace ZThread {

class ThreadImpl;

/**
 * @class Runnable
 *
 * @author Eric Crahen <crahen@cse.buffalo.edu>
 * @date <2002-03-04T20:36:26-0500>
 * @version 2.0.0a
 *
 * Encapsulates a Runnable task.
 */
class ZTHREAD_API Runnable {
  public:

  /**
   * Runnables should never throw in thier destructors
   */
  virtual ~Runnable() throw() {}

  /**
   * Task to be performed in another thread of execution
   */
  virtual void run() throw() = 0;

};


/**
 * @class Thread
 *
 * @author Eric Crahen <crahen@cse.buffalo.edu>
 * @date <2002-03-04T20:36:26-0500>
 * @version 2.0.0a
 *
 * A special Runnable object that reflects each thread of execution
 * in a flexible way. Thread objects provided an excellent abstraction
 * for mutlithreading. They also provided the underlying mechanics to
 * allow the synchronization objects to be interruptable. This is very
 * important because that is a key factor in this framework
 *
 * A Thread can run a task in another thread of execution
 *
 * @code
 * class Task : public Runnable { ... }
 * @endcode
 * ...
 * @code
 * Task z;
 * Thread t;
 * t.run(&z);
 * @endcode
 * ...
 *
 * Or it can be extended to have its task built in
 *
 * @code
 *
 * class ThreadEx : public Thread {
 * ...
 * virtual void run() {
 * // do something
 * }
 * ...
 * };
 *
 * ThreadEx t; 
 * t.start();
 *
 * @endcode
 * Interrupting:
 *
 * Threads can be interrupted - any synchronization object can examine
 * a threads state while waiting and throw an Interrupted_Exception
 * instead of blocking indefinitely. This is not a permanent state. Once
 * it has been checked, it is reset to not being interrupted so it can
 * continue to perform other tasks
 */
class ZTHREAD_API Thread : public Runnable { 

  //! Used to provide a hook for other libraries
  static FastThreadLocal<void*> _interruptKey;

  ThreadImpl *_impl;

  //! Used internally
  Thread(ThreadImpl*);

  private:

  // Disable copy constructors
  Thread(const Thread&);
  Thread& operator=(const Thread&);
  
  public:

  //! Priorities
  typedef enum {

    PRI_NORMAL,
    PRI_HIGH,
    PRI_LOW

  } PRIORITY;

  /**
   * Create a new thread object that can execute tasks in another thread
   * of execution
   *
   * @exception Initialization_Exception - thrown if there are not 
   * enough resources to do this
   */
  Thread()
    throw(Synchronization_Exception);

  /**
   * Destroy this Thread object
   */
  virtual ~Thread()
    throw();
  
  /**
   * Function provided mainly for convenience. Just another way to get a
   * reference to the Thread from a Thread object
   *
   * @return Thread* for self;
   */
  inline Thread* operator->() { return this; }
  
  /**
   * Compare two threads for equivalence
   */
  inline bool equals(const Thread& t) const {
    return _impl == t._impl;
  }

  /**
   * Compare two Threads to see if they refer to the same 
   * thread in OS.
   *
   * @param const Thread&
   * @return bool
   */
  inline bool operator==(const Thread& t) const {
    return equals(t);
  }

  /**
   * Killing a thread prevents it from blocking in the future and will unblock
   * it immeditaley if it is blocked. Synchronziation objects will throw
   * an Unexpected_Exceptions if you attempt to a blocking operation from the 
   * context of a killed thread. Killed threads cannot be joined, once killed
   * a thread will behave as a daemon thread would in that regard.
   *
   * This lets you respond to a thread being killed and exit as fast as 
   * possible as safely as possible.
   *
   * This method is virtual to allow for more specific behavior in 
   * subclasses. The Worker class, for instance, is a simple example of 
   * how this feature is used.
   * 
   * @exception Unexpected_Exception thrown if this thread is already KILLED 
   * @exception InvalidOp_Exception thrown if the thread being joined is invalid 
   * (e.g. KILLED, JOINED, etc)
   */
  virtual void kill()
    throw(Synchronization_Exception);

  /**
   * Wait for the thread represented by this object to exit.
   * Only one thread can wait on any other thread.
   *
   * @param timeout maximum number of milliseconds to wait
   * on this thread. If the timeout is 0, an infinite wait is
   * performed.
   *
   * @exception Deadlock_Exception thrown if thread attempts to join itself.
   * @exception InvalidOp_Exception thrown if the thread being joined is invalid 
   * (e.g. KILLED, JOINED, etc)
   * @exception Interrupted_Exception thrown if the joining thread is INTERRUPTED.
   * @exception Unexpected_Exception thrown if the joining thread is KILLED.
   */
  bool join(unsigned long timeout = 0) 
    throw(Synchronization_Exception);

  /**
   * This can be implemented by subclasses to create a thread with 
   * a built in task.
   */
  virtual void run() throw(); 

  /**
   * Runs the built-in task (the run() method) is any. The default
   * built-in task will exit immediately. This should not be used
   * unless the thread has been extended as shown above
   *
   * @exception Synchronization_Exception - thrown if there is an
   * error starting the thread
   */
  void start() 
    throw(Synchronization_Exception);
  
  /**
   * Run a given task. Each thread can execute one task
   * 
   * @exception InvalidOp_Exception - thrown if a thread has already
   * been assigned a task - or if you attempt to run tasks with a thread
   * you did not create
   *
   * @exception Synchronization_Exception - thrown if there is an
   * error starting the thread
   */
  void run(Runnable *target) 
    throw(Synchronization_Exception);
  
  /** 
   * Interrupt a wait this thread may be blocking on. If the thread is not 
   * currently blocked the next time the thread starts an interruptable wait 
   * it will throw an exception. If isInterrupted() is called before an
   * interruptable wait is performed, then the interrupted status of the
   * thread will be reset and the next interruptable wait will no longer
   * cause an exception.
   *
   * A Thread can interrupt() it self - however, this will only reset its
   * interrupted status. This allows for the creation of more elegant 
   * extended Thread classes (like the Timer)
   *
   * @see interruptKey
   *
   * @exception Synchronization_Exception - thrown if a killed or joined
   * thread is interrupted
   */
  void interrupt() 
    throw(Synchronization_Exception);
    
  /**
   * Change the priority of this Thread. 
   *
   */
  void setPriority(Thread::PRIORITY)
    throw(Synchronization_Exception);

  /**
   * Get the priority of this Thread. 
   *
   */
  Thread::PRIORITY getPriority()
    throw(Synchronization_Exception);


  /**
   * Check the state of the thread. This will always reset the state 
   * to not interrupted so the appropriate action should be taken. 
   *
   * If this method is called from the threads own context, the interrupted
   * status of the thread is reset.
   *
   * @return bool - true was interrupted, false was not interrupted
   */
  bool isInterrupted()
    throw();

  /**
   * Check the state of the thread. 
   *
   * @return bool - true was killed, false was not killed
   */
  virtual bool isKilled()
    throw();
  
  
  /**
   * Check the state of this thread to determine weather or not it 
   * has been marked as a daemon thread.
   *
   * @return bool - result
   */
  bool isDaemon()
    throw();

  /**
   * Change the status of this thread so that is now treated as a daemon
   * thread. A daemon thread should not be joined, it will execute normally
   * and its destructor can safely be invoked without first join()ing it.
   * It will be join()ed by ZThreads when the program exits.
   *
   * This address some of the static destruction problems that can occur.
   * See the README for details
   *
   * Two important things happen to daemon threads:
   *
   * This thread will be joined *before* static destructors execute. This
   * is automatic, the daemon thread should not be joined explicitly
   *
   * This thread will recieve an interrupt() before it is joined if the 
   * setNotify() method is also invoked.
   *
   * @param bool - flag, set to daemon if true, otherwise set back to a
   * normal user thread that can be joined.
   *
   * @return bool - success of operation
   */
  void setDaemon(bool flag)
    throw(Synchronization_Exception);


  /**
   * Indicate this thread should recieve a notification, via interrupt(),
   * if this thread is marked as a daemon thread and the system is preparing
   * to exit - but has not yet deconstructed static objects. 
   *
   * The system will wait for daemon threads to exit before this is done. 
   * For some types of daemon threads running a lone task, for instance, 
   * perodic polling or something similar, it is appropriate for them
   * to be interrupt()ed. In other cases, Executor worker threads for 
   * example, the Exectuor is in control of the threads, those threads may
   * not need or want that interrupt() since they are already working
   * with another object to determine when they should exit.
   *
   * The default is false, a thread must ask to get this notification
   *
   * @param bool - if true, thread should be notified if it is a daemon and
   * the system is waiting to exit
   *
   * @return bool - success of operation
   */
  void setNotify(bool flag)
    throw(Synchronization_Exception);

  /**
   * Check to see if this thread is asking to be notified of the system
   * exiting. 
   *
   * @see setNotfiy()
   *
   * @param bool - notify status
   */
  bool wantNotify()
    throw();

  /** 
   * Put the currently executing thread to sleep for a given amount of
   * time. This is an interruptable wait.
   *
   * @param unsigned long - amount of time to wait (milliseconds)
   *
   * @exception Interrupted_Exception - thrown if this wait was interrupted
   */
  static void sleep(unsigned long)
     throw(Synchronization_Exception);
  
  /**
   * Cause the currently executing thread to yield, allowing the scheduler
   * to assign some execution time to another thread.
   */
  static void yield() 
    throw();

  /** 
   * Get a reference to the currently executing thread. You can not use
   * this reference to execute tasks.
   *
   * @exception Synchronization_Exception - thrown if zthreads shutdown
   * before your calling this. Only happens if you use alot of static objects
   * that attempt to invoke zthreads methods after zthreads objects have gone
   * out of scope when the program is terminating.
   *
   * You can handle this situation by trying to catch an InvalidOp_Exception
   * around any code you suspect may be in this situation and then respond
   * accordingly.
   */
  static Thread current()
    throw(Synchronization_Exception);


  /**
   * Get a reference to a default ThreadLocal key. This key will always
   * contain some information that is specific to a particular platform.
   *
   * This is used to develop software that wants to react to
   * a Thread::interrupt() invocation.
   *
   * WIN32 details:
   *
   * The Win32 system provides a rich set of function that work with event
   * handles. Because there are so many ways to use these handles creatively
   * to handle various situation, the interruptKey() on a Win32 system will
   * contain the value of a HANDLE. This handle can be used with functions
   * like WaitForMutlipleObjects() or WSAEventSelect(), it will be 
   * notified with SetEvent() as a thread was interrupted.
   *
   * POSIX details:
   *
   * SIG_ALRM will be generated and should interrupt any i/o that is 
   * in progress. Most POSIX functions will return EINTR in such a 
   * situation. Example:
   *
   * @code
   *
   * char buf[64];
   * size_t sz = 64;
   * 
   * do {
   * 
   *   ssize_t n = read(fd, buf, sz);
   *
   *   if(n < 0 && errno == EINTR && Thread::current()->isInterrupted()) {
   *     // Take some action
   *     throw SomeKindOfInterruptedException();
   *   }
   *
   * } while(n < 0 && errno == EINTR);
   * 
   * @endcode
   * 
   * To write some piece of code that can be notified of a Thread::interrupt()
   * if it is performing some action that does not return EINTR another
   * method is provided. The interruptKey() will contain the address of a
   * sigjmp_buf. If the user sets this value to something other than null,
   * the Thread::interrupt() will use a siglongjmp after invoking the signal
   * The threads interrupt() method will also clear this address after it has
   * been used so that double notifications do not occur.
   * Example:
   *
   * @code
   *
   *  // Implement for a function that ignores EINTR
   *  sigjmp_buf timeout_jmp;
   *  if(sigsetjmp(timeout_jmp, 1) != 0) {
   *    // Take some action
   *    throw SomeKindOfInterruptedException();
   *  }
   *
   *  // Enable the timeout
   *  ZThread::Thread::interruptKey().set(&timeout_jmp);
   *
   *  // Do some lengthy operation.
   *
   *  // Disable the timeout
   *  ZThread::Thread::interruptKey().set(NULL);
   *
   * @endcode
   *
   * @return const FastThreadLocal&
   */
  inline static const FastThreadLocal<void*>& interruptKey() throw() {
    return _interruptKey;
  }

}; /* Thread */
  
}; 

#endif



