/* threaded_queue.h

   Written by Robert Collins <rbtcollins@hotmail.com>

This file is part of Cygwin.

This software is a copyrighted work licensed under the terms of the
Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
details. */

#ifndef _THREADED_QUEUE_
#define _THREADED_QUEUE_

/*****************************************************************************/

/* a specific request */

class queue_request
{
public:
  queue_request *_next;

  queue_request () : _next (NULL) {}
  virtual ~queue_request ();

  virtual void process () = 0;
};

/*****************************************************************************/

/* a queue to allocate requests from n submission loops to x worker threads */

class queue_submission_loop;

class threaded_queue
{
public:
  threaded_queue (size_t initial_workers = 1);
  ~threaded_queue ();

  void add_submission_loop (queue_submission_loop *);

  bool running () const { return _running; }

  bool start ();
  bool stop ();

  void add (queue_request *);

private:
  LONG _workers_count;
  LONG _workers_busy;
  bool _running;

  queue_submission_loop *_submitters_head;

  long _requests_count;		// Informational only.
  queue_request *_requests_head;

  CRITICAL_SECTION _queue_lock;
  HANDLE _requests_sem;		// == _requests_count

  static DWORD WINAPI start_routine (LPVOID /* this */);

  void create_workers (size_t initial_workers);
  void worker_loop ();
};

/*****************************************************************************/

/* parameters for a request finding and submitting loop */

class queue_submission_loop
{
  friend class threaded_queue;

public:
  queue_submission_loop (threaded_queue *, bool ninterruptible);
  virtual ~queue_submission_loop ();

  bool start ();
  bool stop ();

  threaded_queue *queue () { return _queue; };

protected:
  bool _running;
  HANDLE _interrupt_event;
  threaded_queue *const _queue;

private:
  bool _interruptible;
  HANDLE _hThread;
  DWORD _tid;
  queue_submission_loop *_next;

  static DWORD WINAPI start_routine (LPVOID /* this */);
  virtual void request_loop () = 0;
};

#ifdef __cplusplus

/*---------------------------------------------------------------------------*
 * Some type-safe versions of the various interlocked functions.
 *---------------------------------------------------------------------------*/

template <typename T> T *
TInterlockedExchangePointer (T **lvalue, T *rvalue)
{
  return reinterpret_cast<T *>
    (InterlockedExchangePointer (reinterpret_cast<void **> (lvalue),
				 reinterpret_cast<void *> (rvalue)));
}

template <typename T> T *
TInterlockedCompareExchangePointer (T **lvalue, T *rvalue1, T *rvalue2)
{
  return reinterpret_cast<T *>
    (InterlockedCompareExchangePointer (reinterpret_cast<void **> (lvalue),
					reinterpret_cast<void *> (rvalue1),
					reinterpret_cast<void *> (rvalue2)));
}

#endif /* __cplusplus */

#endif /* _THREADED_QUEUE_ */
