#ifndef _BACKUP_THREAD_H
#define _BACKUP_THREAD_H

#include <backup_engine.h>
#include <backup/image_info.h>

/**
   Macro for error handling.
*/
#define SET_STATE_TO_ERROR_AND_DBUG_RETURN {                                 \
    DBUG_PRINT("error",("driver got an error at %s:%d",__FILE__,__LINE__)); \
    DBUG_RETURN(backup::ERROR); }

/**
   Locking of tables goes through several states.
*/
typedef enum {
  LOCK_NOT_STARTED,
  LOCK_IN_PROGRESS,
  LOCK_ACQUIRED,
  LOCK_DONE,
  LOCK_ERROR,
  LOCK_SIGNAL
} LOCK_STATE;

using backup::result_t;
using backup::Table_list;

/**
   backup_thread_for_locking

   This method creates a new thread and opens and locks the tables.

   @param[in] arg  List of arguments.
*/
pthread_handler_t backup_thread_for_locking(void *arg);

/**
  Locking_thread
 
  @brief Adds variables for using a locking thread for opening tables.
 
  The Backup_thread structure contains a mutex and condition variable
  for using a thread to open and lock the tables. This is meant to be a
  generic class that can be used elsewhere for opening and locking tables.

  @note This class correctly handles the separate locking thread. However, 
  the class itself is *not* multi-thread safe. An instance of Locking_thread_st
  should be used by one thread only. In particular, calling 
  @c start_locking_thread() from one thread and @c kill_locking_thread() from
  another thread running in parallel is not guaranteed to work.
*/
struct Locking_thread_st
{
public:
  Locking_thread_st();
  ~Locking_thread_st();

  pthread_mutex_t THR_LOCK_thread; ///< mutex for thread variables
  pthread_cond_t COND_thread_wait; ///< condition variable for wait
  pthread_mutex_t THR_LOCK_caller; ///< mutex for thread variables
  pthread_cond_t COND_caller_wait; ///< condition variable for wait

  TABLE_LIST *tables_in_backup;    ///< List of tables used in backup
  THD *lock_thd;                   ///< Locking thread pointer
  LOCK_STATE lock_state;           ///< Current state of the lock call
  THD *m_thd;                      ///< Pointer to current thread struct.
  String thd_name;                 ///< Name of locking thread
  /// Indicates if the locking thread has been started.
  my_bool m_thread_started;

  result_t start_locking_thread(const char *tname);
  void kill_locking_thread();
  void wait_until_locking_thread_dies();

}; // Locking_thread_st

/**
  @class Backup_thread_driver
 
  @brief Adds variables for using a locking thread for opening tables.
 
  The Backup_thread_driver class extends the Backup_driver class by adding
  a mutex and condition variable for using a thread to open and lock the 
  tables.
 
  @see Backup_driver
*/
class Backup_thread_driver : public Backup_driver
{
public:

  /// Constructor
  Backup_thread_driver(const backup::Table_list &tables)
    :Backup_driver(tables) { locking_thd = new Locking_thread_st(); }
  /// Destructor
  ~Backup_thread_driver() { delete locking_thd; }

  Locking_thread_st *locking_thd;  ///< Pointer to locking thread data.
}; // Backup_thread_driver class


#endif

