/*
 *
 *  Copyright (C) 1997-2005, OFFIS
 *
 *  This software and supporting documentation were developed by
 *
 *    Kuratorium OFFIS e.V.
 *    Healthcare Information and Communication Systems
 *    Escherweg 2
 *    D-26121 Oldenburg, Germany
 *
 *  THIS SOFTWARE IS MADE AVAILABLE,  AS IS,  AND OFFIS MAKES NO  WARRANTY
 *  REGARDING  THE  SOFTWARE,  ITS  PERFORMANCE,  ITS  MERCHANTABILITY  OR
 *  FITNESS FOR ANY PARTICULAR USE, FREEDOM FROM ANY COMPUTER DISEASES  OR
 *  ITS CONFORMITY TO ANY SPECIFICATION. THE ENTIRE RISK AS TO QUALITY AND
 *  PERFORMANCE OF THE SOFTWARE IS WITH THE USER.
 *
 *  Module:  ofstd
 *
 *  Author:  Marco Eichelberg
 *
 *  Purpose: Provides operating system independent abstractions for basic
 *           multi-thread concepts: threads, thread specific data,
 *           semaphores, mutexes and read/write locks. The implementation
 *           of these classes supports the Solaris, POSIX and Win32
 *           multi-thread APIs.
 *
 *  Last Update:      $Author: meichel $
 *  Update Date:      $Date: 2005/12/08 16:06:08 $
 *  CVS/RCS Revision: $Revision: 1.9 $
 *  Status:           $State: Exp $
 *
 *  CVS/RCS Log at end of file
 *
 */


#ifndef OFTHREAD_H
#define OFTHREAD_H

#include "dcmtk/config/osconfig.h"
#include "dcmtk/ofstd/oftypes.h"  /* for class OFBool */
#include "dcmtk/ofstd/ofstring.h" /* for class OFString */

/** Stub function with extern "C" linkage that is passed as a function pointer
 *  to the system function that creates the thread.
 *  @param arg pointer to the OFThread instance to be started, passed as void pointer.
 */
extern "C"
{
#ifdef HAVE_WINDOWS_H
  unsigned int __stdcall thread_stub(void *arg);
#else
  void *thread_stub(void *arg);
#endif
}


/** provides an operating system independent abstraction for threads.
 *  Threads are executed asynchronously in parallel to the main thread
 *  of the process. On multi-processor machines threads may run on
 *  different CPUs if the operating system permits.
 *  This class is abstract. Deriving classes must implement the run()
 *  method which contains the code executed by the thread.
 */
class OFThread
{
public:

  /** default constructor. The new thread is not started immediately
   *  upon creation of the OFThread object. Calling the start()
   *  method causes the creation of the thread.
   */
  OFThread();

  /** destructor. Destruction of an OFThread object does not cause
   *  the referenced thread to be stopped and may result in undefined
   *  behaviour if the derived class maintains thread specific data
   *  in this object (which is not recommended).
   *  The join() method should be called prior to destruction
   *  of the thread object to make sure a thread has terminated.
   */
  virtual ~OFThread();

  /** adds a new thread of control to the  current process. The main()
   *  procedure itself is a single thread of control. Each thread executes
   *  simultaneously  with  all  the other  threads  within  the  calling
   *  process. A newly created thread shares all of  the  calling  process'
   *  global data with the other threads in this process except the
   *  execution stack.   The new thread executes the run() method and
   *  terminates upon return from this method or a call to thread_exit()
   *  from within the thread. This method should not be called if a thread
   *  is already running, otherwise a new thread will be started and the
   *  identifier of the old thread will be overwritten, making it
   *  impossible to call join() for the old thread.  It may also result in
   *  undefined behaviour if the derived class maintains thread specific
   *  data in this object (which is not recommended).
   *  @return 0 upon success, an error code otherwise.
   */
  int start();

  /** blocks the calling thread until the thread referenced by the OFThread
   *  object terminates. Several threads cannot wait for the same thread to
   *  complete; one  thread  will  complete the join() method successfully
   *  others may or may not return OFThread::busy. The method will not
   *  block the calling thread if the target thread has already terminated.
   *  @return 0 upon success, OFThread::busy if another thread is already
   *    waiting for the termination of the target thread,
   *    an error code otherwise.
   */
  int join();

  /** returns the thread identifier of the thread referenced by the
   *  OFThread object, if the thread has already been started.
   *  Otherwise returns 0. On certain platforms like OSF/1, a thread ID
   *  contains a pointer to a structure. Therefore, thread IDs should
   *  never be compared directly, but always using the equal() method
   *  provided in this class.
   *  @return thread ID of target thread if started, 0 otherwise.
   */
  unsigned long threadID();

  /** checks if the given thread ID matches the thread ID of the thread
   *  referenced by this object.
   *  @param tID thread ID to be compared
   *  @return OFTrue if equal, OFFalse otherwise.
   */
  OFBool equal(unsigned long tID);

  /** converts any of the error codes returned by the methods of this class
   *  into a textual description, which is written into the string object.
   *  @param description string object into which the error description is written.
   *  @param code error code
   */
  static void errorstr(OFString& description, int code);

  /** this constant is returned by the join() method if another thread
   *  is already waiting for termination of the thread referenced by the
   *  OFThread object. Since this value is operating system dependent,
   *  comparisons should always compare the return value of join()
   *  with this constant.
   */
  static const int busy;

protected:

  /** terminates the calling thread, in a similar way that exit()
   *  terminates the calling process. This method does not return.
   */
  static void thread_exit();

  /** returns the thread ID of the calling thread. For a running thread,
   *  this->threadID() and this->self() should return the same value,
   *  but self() is more robust and should be preferred.
   *  On certain platforms like OSF/1, a thread ID
   *  contains a pointer to a structure. Therefore, thread IDs should
   *  never be compared directly, but always using the equal() method
   *  provided in this class.
   *  @return thread ID of the calling thread.
   */
  static unsigned long self();

private:

  /** this method implements the thread that is run by calling the start
   *  method of the OFThread object. Defined as abstract method in OFThread.
   *  It is recommended that derived classes implementing this method
   *  do not rely on attributes of the OFThread object because this might
   *  result in undefined behaviour if another thread deletes or restarts the
   *  OFThread object before the thread has terminated.
   */
  virtual void run() = 0;

#ifdef HAVE_WINDOWS_H
  /** thread handle (Win32 only) */
  unsigned long theThreadHandle;
#endif

  /** thread identifier */
#ifdef HAVE_POINTER_TYPE_PTHREAD_T
  void *theThread;
#else
  unsigned long theThread;
#endif

  /** unimplemented private copy constructor */
  OFThread(const OFThread& arg);

  /** unimplemented private assignment operator */
  OFThread& operator=(const OFThread& arg);

  /** thread stub must be friend to call run() */
#ifdef HAVE_WINDOWS_H
  friend unsigned int __stdcall thread_stub(void *arg);
#else
  friend void *thread_stub(void *arg);
#endif
};


/** provides an operating system independent abstraction for thread
  * specific data. An instance of this class manages a key which is global
  * to all threads in the process but locates data specific to each thread.
  * Each thread can set a different value once the object has been created.
  * Upon creation, the value NULL is assigned for all threads. This class
  * does not perform any memory management on the objects pointed to.
  * Threads must ensure on their own that the data pointed to by the thread
  * specific data key is freed upon termination of the thread.
  */
class OFThreadSpecificData
{
public:

  /** default constructor */
  OFThreadSpecificData();

  /** destructor. Deletes all thread specific key values (pointers), but
   *  not the objects pointed to.
   */
  ~OFThreadSpecificData();

  /** checks whether creation of the object was successful.
   *  @return OFTrue if the object was successfully created, OFFalse otherwise.
   */
  OFBool initialized() const;

  /** sets the thread specific value for this object. No attempt is made to
   *  automatically delete the object pointed to at the termination of the
   *  thread.
   *  @param value new pointer to thread-specific data for this object.
   *  @return 0 if successful, an error code otherwise.
   */
  int set(void *value);

  /** retrieves the thread specific value for this object. If no call to set()
   *  has been made for the calling thread before, NULL is returned.
   *  @param value new pointer to thread-specific data for this object
   *    returned in this parameter.
   *  @return 0 if successful, an error code otherwise.
   */
  int get(void *&value);

  /** converts any of the error codes returned by the methods of this class
   *  into a textual description, which is written into the string object.
   *  @param description string object into which the error description is written.
   *  @param code error code
   */
  static void errorstr(OFString& description, int code);

private:

  /** thread specific data key resource */
#ifdef HAVE_CXX_VOLATILE
  volatile
#endif
  void *theKey;

  /** unimplemented private copy constructor */
  OFThreadSpecificData(const OFThreadSpecificData& arg);

  /** unimplemented private assignment operator */
  OFThreadSpecificData& operator=(const OFThreadSpecificData& arg);
};


/** provides an operating system independent abstraction for semaphores.
 *  A semaphore is a non-negative integer counter that is used
 *  to coordinate access to resources. The initial and maximum value of the counter
 *  is defined by the constructor. Each call to wait() decreases
 *  the counter by one and each call to post() increases the count by one.
 *  If a thread calls wait() while the counter is zero, the thread
 *  is blocked until another thread has increased the counter using post().
 */
class OFSemaphore
{
public:

  /** constructor.
   *  @param numResources is the initial and maximum value for the semaphore.
   */
  OFSemaphore(unsigned int numResources);

  /** destructor */
  ~OFSemaphore();

  /** checks whether creation of the object was successful.
   *  @return OFTrue if the object was successfully created, OFFalse otherwise.
   */
  OFBool initialized() const;

  /** blocks the calling thread until the semaphore counter is greater than zero
   *  and then atomically decreases the counter.
   *  @return 0 upon success, an error code otherwise.
   */
  int wait();

  /** atomically decreases the counter if it is larger than zero,
   *  otherwise returns OFSemaphore::busy.
   *  @return 0 upon success, OFSemaphore::busy if the semaphore is already locked,
   *    an error code otherwise.
   */
  int trywait();

  /** atomically increases the counter. If threads are blocked on the semaphore,
   *  at least one of them is unblocked.
   *  @return 0 upon success, an error code otherwise.
   */
  int post();

  /** converts any of the error codes returned by the methods of this class
   *  into a textual description, which is written into the string object.
   *  @param description string object into which the error description is written.
   *  @param code error code
   */
  static void errorstr(OFString& description, int code);

  /** this constant is returned by the trywait() method if the semaphore
   *  is already locked. Since this value is operating system dependent,
   *  comparisons should always compare the return value of trywait()
   *  with this constant.
   */
  static const int busy;

private:
  /** semaphore resource */
#ifdef HAVE_CXX_VOLATILE
  volatile
#endif
  void * theSemaphore;

  /** unimplemented private copy constructor */
  OFSemaphore(const OFSemaphore& arg);

  /** unimplemented private assignment operator */
  OFSemaphore& operator=(const OFSemaphore& arg);
};


/** provides an operating system independent abstraction for mutexes
 *  (mutual exclusion locks).
 *  Mutexes prevent multiple threads from simultaneously executing critical
 *  sections of code which access shared data. A successful call for a
 *  mutex lock by way of lock() will cause another thread that is also
 *  trying to lock the same mutex to block until the owner thread unlocks
 *  it by way of unlock().
 */
class OFMutex
{
public:

  /** default constructor */
  OFMutex();

  /** destructor */
  ~OFMutex();

  /** checks whether creation of the object was successful.
   *  @return OFTrue if the object was successfully created, OFFalse otherwise.
   */
  OFBool initialized() const;

  /** locks the mutex object. If the mutex is already locked, the calling
   *  thread blocks until the mutex is freed; If the current owner of a
   *  mutex tries to relock the mutex, it may or may not result in
   *  deadlock.
   *  @return 0 upon success, an error code otherwise.
   */
  int lock();

  /** tries to lock the mutex object. If the mutex is already locked,
   *  returns OFMutex::busy.
   *  @return 0 upon success, OFMutex::busy if the mutex is already locked,
   *    an error code otherwise.
   */
  int trylock();

  /** releases the lock on the mutex object. The mutex must be locked and
   *  the calling thread must be the owner of the lock, otherwise the
   *  behaviour is undefined. If there are threads blocked on the mutex
   *  when unlock() is called, one of them is unblocked and receives
   *  ownership of the mutex lock.
   *  @return 0 upon success, an error code otherwise.
   */
  int unlock();

  /** converts any of the error codes returned by the methods of this class
   *  into a textual description, which is written into the string object.
   *  @param description string object into which the error description is written.
   *  @param code error code
   */
  static void errorstr(OFString& description, int code);

  /** this constant is returned by the trylock() method if the mutex
   *  is already locked. Since this value is operating system dependent,
   *  comparisons should always compare the return value of trylock()
   *  with this constant.
   */
  static const int busy;

private:
  /** mutex resource */
#ifdef HAVE_CXX_VOLATILE
  volatile
#endif
  void * theMutex;

  /** unimplemented private copy constructor */
  OFMutex(const OFMutex& arg);

  /** unimplemented private assignment operator */
  OFMutex& operator=(const OFMutex& arg);
};


/** provides an operating system independent abstraction for read/write
 *  locks. Many threads can have simultaneous read-only access to data,
 *  while only one thread can have write access at any given time.
 *  Multiple read access with single write access is controlled by
 *  read/write locks, which are generally used to protect data that is
 *  frequently searched.
 */
class OFReadWriteLock
{
public:

  /** default constructor */
  OFReadWriteLock();

  /** destructor */
  ~OFReadWriteLock();

  /** checks whether creation of the object was successful.
   *  @return OFTrue if the object was successfully created, OFFalse otherwise.
   */
  OFBool initialized() const;

  /** gets a read lock. If the read/write lock is currently locked for
   *  writing, the calling thread blocks until the write lock is freed.
   *  Multiple threads may simultaneously hold a read lock on a read/write
   *  lock.
   *  @return 0 upon success, an error code otherwise.
   */
  int rdlock();

  /** gets a write lock. If the read/write lock is currently locked for
   *  reading or writing, the calling thread blocks until all the read and
   *  write locks are freed. At any given time, only one thread may have a
   *  write lock on a read/write lock.
   *  @return 0 upon success, an error code otherwise.
   */
  int wrlock();

  /** trys to get a read lock. If the read/write lock is locked for
   *  writing, returns OFReadWriteLock::busy.
   *  @return 0 upon success, OFReadWriteLock::busy if the read/write lock
   *    is already locked, an error code otherwise.
   */
  int tryrdlock();

  /** trys to get a write lock. If the read/write lock is currently locked
   *  for reading or writing, returns OFReadWriteLock::busy.
   *  @return 0 upon success, OFReadWriteLock::busy if the read/write lock
   *    is already locked, an error code otherwise.
   */
  int trywrlock();

  /** unlocks the read/write lock. The read/write lock must be locked and
   *  the calling thread must be the owner of the lock, otherwise the
   *  behaviour is undefined. One of the other threads that is waiting for
   *  the read/write lock to be freed will be unblocked, provided there are
   *  other waiting threads.
   *  @return 0 upon success, an error code otherwise.
   */
  int unlock();

  /** converts any of the error codes returned by the methods of this class
   *  into a textual description, which is written into the string object.
   *  @param description string object into which the error description is written.
   *  @param code error code
   */
  static void errorstr(OFString& description, int code);

  /** this constant is returned by the tryrdlock() and trywrlock() methods
   *  if the read/write lock is already locked. Since this value is operating
   *  system dependent, comparisons should always compare the return value
   *  of tryrdlock() and trywrlock() with this constant.
   */
  static const int busy;

private:
  /** read/write lock resource */
#ifdef HAVE_CXX_VOLATILE
  volatile
#endif
  void * theLock;

  /** unimplemented private copy constructor */
  OFReadWriteLock(const OFReadWriteLock& arg);

  /** unimplemented private assignment operator */
  OFReadWriteLock& operator=(const OFReadWriteLock& arg);
};

#endif

/*
 *
 * CVS/RCS Log:
 * $Log: ofthread.h,v $
 * Revision 1.9  2005/12/08 16:06:08  meichel
 * Changed include path schema for all DCMTK header files
 *
 * Revision 1.8  2004/08/03 16:44:16  meichel
 * Updated code to correctly handle pthread_t both as an integral integer type
 *   (e.g. Linux, Solaris) and as a pointer type (e.g. BSD, OSF/1).
 *
 * Revision 1.7  2003/12/05 10:37:41  joergr
 * Removed leading underscore characters from preprocessor symbols (reserved
 * symbols). Updated copyright date where appropriate.
 *
 * Revision 1.6  2003/07/04 13:29:51  meichel
 * Replaced forward declarations for OFString with explicit includes,
 *   needed when compiling with HAVE_STD_STRING
 *
 * Revision 1.5  2003/06/06 10:31:04  meichel
 * Added volatile keyword to data pointers in multi-thread wrapper classes
 *
 * Revision 1.4  2002/02/27 14:13:19  meichel
 * Changed initialized() methods to const. Fixed some return values when
 *   compiled without thread support.
 *
 * Revision 1.3  2001/06/01 15:51:36  meichel
 * Updated copyright header
 *
 * Revision 1.2  2000/06/26 09:27:26  joergr
 * Replaced _WIN32 by HAVE_WINDOWS_H to avoid compiler errors using CygWin-32.
 *
 * Revision 1.1  2000/03/29 16:41:23  meichel
 * Added new classes providing an operating system independent abstraction
 *   for threads, thread specific data, semaphores, mutexes and read/write locks.
 *
 *
 */
