/* -*- C++ -*- */

//=============================================================================
/**
 *  @file    Object_Manager.h
 *
 *  @author David L. Levine <levine@cs.wustl.edu>
 *  @author Matthias Kerkhoff
 *  @author Per Andersson
 */
//=============================================================================

#ifndef ACE_OBJECT_MANAGER_H
#define ACE_OBJECT_MANAGER_H
#include /**/ "ace/pre.h"

#include /**/ "ace/ACE_export.h"
#include "ace/Object_Manager_Base.h"
#include "ace/Global_Macros.h"

#if !defined (ACE_LACKS_PRAGMA_ONCE)
# pragma once
#endif /* ACE_LACKS_PRAGMA_ONCE */

ACE_BEGIN_VERSIONED_NAMESPACE_DECL

// Forward declarations.
class ACE_Object_Manager_Preallocations;
class ACE_Sig_Adapter;
class ACE_Sig_Set;

ACE_END_VERSIONED_NAMESPACE_DECL

#if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0)

ACE_BEGIN_VERSIONED_NAMESPACE_DECL

  class ACE_Mutex;
  class ACE_Null_Mutex;
  class ACE_Thread_Mutex;
  class ACE_Recursive_Thread_Mutex;
  class ACE_RW_Thread_Mutex;

ACE_END_VERSIONED_NAMESPACE_DECL

#  include "ace/Recursive_Thread_Mutex.h"
#endif /* ACE_MT_SAFE */

ACE_BEGIN_VERSIONED_NAMESPACE_DECL

// only used by ACE_OS_Object_Manager::ctor
# if defined (ACE_WIN32)
// Default WIN32 structured exception handler.
int ACE_SEH_Default_Exception_Selector (void *);
int ACE_SEH_Default_Exception_Handler (void *);
# endif /* ACE_WIN32 */

class ACE_Cleanup_Info_Node;
template <class T> class ACE_Cleanup_Adapter;

// Configuration parameters.
#if !defined (ACE_MAX_MANAGED_OBJECTS)
# define ACE_MAX_MANAGED_OBJECTS 128
#endif /* ! ACE_MAX_MANAGED_OBJECTS */

#if !defined (ACE_APPLICATION_PREALLOCATED_OBJECT_DECLARATIONS)
# define ACE_APPLICATION_PREALLOCATED_OBJECT_DECLARATIONS
#endif /* ! ACE_APPLICATION_PREALLOCATED_OBJECT_DECLARATIONS */

#if !defined (ACE_APPLICATION_PREALLOCATED_ARRAY_DECLARATIONS)
# define ACE_APPLICATION_PREALLOCATED_ARRAY_DECLARATIONS
#endif /* ! ACE_APPLICATION_PREALLOCATED_ARRAY_DECLARATIONS */

/**
 * @class ACE_Object_Manager
 *
 * @brief Manager for ACE library services and singleton cleanup.
 *
 * The ACE_Object_Manager manages cleanup of objects, typically
 * singletons, at program termination.  In addition to managing
 * the cleanup of the ACE library, it provides an interface for
 * application to register objects to be cleaned up.
 * This class also shuts down ACE library services, so that they
 * can reclaim their storage, at program termination.  It works
 * by creating a static instance whose destructor gets called
 * along with those of all other static objects.  Hooks are
 * provided for application code to register objects and arrays
 * for cleanup, e.g., destruction.  The order of such cleanup
 * calls is in the reverse order of registration, i.e., that
 * last object/array to register gets cleaned up first.
 * The ACE_Object_Manager API includes ACE_Managed_Object.  That
 * class is contained in a separate file because it is a
 * template class, and some compilers require that template and
 * non-template class definitions appear in separate files.
 * Please see ace/Managed_Object.h for a description of that
 * part of the API.  In summary, ACE_Managed_Object provides two
 * adapters, the ACE_Cleanup_Adapter and ACE_Managed_Object
 * template classes for adapting objects of any type to be
 * easily managed by the ACE_Object_Manager.  There are several
 * mechanisms for adapting objects and arrays for cleanup at
 * program termination, in roughly increasing order of ease-of-use:
 * 1) Derive the object's class from ACE_Cleanup.
 * 2) Allow the ACE_Object_Manager to both dynamically allocate
 * and deallocate the object.
 * 3) Provide an <ACE_CLEANUP_FUNC> cleanup hook for the object or
 * array.
 * 4) Allow the ACE_Object_Manager to both preallocate the object
 * or array, either statically in global data or dynamically on
 * the heap, when its singleton instance is construction.
 *
 * There are also several mechanisms for registering objects and
 * arrays for cleanup.  In decreasing order of flexibility and
 * complexity (with the exception of the last mechanism):
 *
 * 1) ACE_Object_Manager::at_exit (void *object,
 * ACE_CLEANUP_FUNC cleanup_hook,
 * void *param);
 * can be used to register any object or array for any
 * cleanup activity at program termination.
 * 2) ACE_Object_Manager::at_exit (ACE_Cleanup *object,
 * void *param = 0);
 * can be used to register an ACE_Cleanup object
 * for any cleanup activity at program termination.
 * The final mechanism is not general purpose, but can only
 * be used to allocate objects and arrays at program startup:
 * 3) ACE_Managed_Object::get_preallocated_object
 * (ACE_Object_Manager::Preallocated_Object id);
 * and
 * ACE_Managed_Object::get_preallocated_array
 * (ACE_Object_Manager::Preallocated_Array id);
 * can only be used to allocate objects at program startup,
 * either in global data or on the heap (selected at compile
 * time).  These are intended to replace static locks, etc.
 * Instead of creating a static ACE_Object_Manager instance, one
 * can alternatively be created on the stack of the main program
 * thread.  It is created just after entry to ::main (int, char
 * *[]), and before any existing code in that function is
 * executed.  To enable this alternative, add #define
 * ACE_HAS_NONSTATIC_OBJECT_MANAGER before including the platform
 * specific config-* file in ace/config.h prior to
 * building the ACE library and your applications.  This #define
 * is enabled in some config files that are supplied with ACE.
 *
 * To ensure a static object manager is used, #undef
 * ACE_HAS_NONSTATIC_OBJECT_MANAGER *after* including the platform
 * specific config-* file.
 * Note that the ACE_Object_Manager _must_ be created before
 * any threads are spawned by the program.
 * If ACE_HAS_NONSTATIC_OBJECT_MANAGER is not #defined, the ACE
 * library creates a static, singleton ACE_Object_Manager instance.
 * The instance is placed in global program data, and constructed
 * via a static object constructor.  If ACE_HAS_NONSTATIC_OBJECT_MANAGER
 * is #defined, the ACE_Object_Manager instance is created on the stack
 * of the main program thread, as noted above.
 *
 * With ACE_HAS_NONSTATIC_OBJECT_MANAGER enabled, the ACE
 * library has no static objects that require destruction.
 * However, there are two drawbacks to using it:
 * 1) main (int, char *[]) must be declared with arguments, even
 * if they're not used.  All of ACE is converted to this, so
 * just applications have to be concerned with it.
 * 2) If there any static objects that depend on those that are
 * cleaned up by the Object_Manager, they'll get cleaned up too
 * late.  The ACE tests do not violate this requirement.
 * However, applications may have trouble with it.
 * NOTE on the use of <::exit> -- <::exit> does not destroy
 * automatic objects.  Therefore, if
 * ACE_HAS_NONSTATIC_OBJECT_MANAGER is enabled, the
 * ACE_Object_Manager instance will *not* be destroyed if
 * <::exit> is called!  However, <ACE_OS::exit> will properly
 * destroy the ACE_Object_Manager.  It is highly recommended
 * that <ACE_OS::exit> be used instead of <::exit>.
 *
 * However, <::exit> and <ACE_OS::exit> are tricky to use
 * properly, especially in multithread programs.  It is much
 * safer to throw an exception (or simulate that effect) that
 * will be caught by <main> instead of calling exit.  Then,
 * <main> can perform any necessary application-specific cleanup
 * and return the status value.  In addition, it's usually best
 * to avoid calling <::exit> and <ACE_OS::exit> from threads
 * other than the main thread.  Thanks to Jeff Greif
 * <jmg@trivida.com> for pointing out that <::exit> doesn't
 * destroy automatic objects, and for developing the
 * recommendations in this paragraph.
 *
 * Instead of creating a static ACE_Object_Manager, or letting
 * ACE create it on the stack of <main> for you, another
 * alternative is to #define
 * ACE_DOESNT_INSTANTIATE_NONSTATIC_OBJECT_MANAGER.  With that
 * #define, the application must create the ACE_Object_Manager.
 * The recommended way is to call <ACE::init> at the start of
 * the program, and call <ACE::fini> at the end.  Alternatively,
 * the application could explicity construct an
 * ACE_Object_Manager.
 */
class ACE_Export ACE_Object_Manager : public ACE_Object_Manager_Base
{

public:
  ACE_ALLOC_HOOK_DECLARE;

  /**
   * Explicitly initialize (construct the singleton instance of) the
   * ACE_Object_Manager.  Returns 0 on success, -1 on failure, and 1
   * if it had already been called.
   */
  virtual int init (void);

  /**
   * Explicitly destroy the singleton instance of the
   * ACE_Object_Manager.  Returns 0 on success, -1 on failure, and 1
   * if it had already been called.
   */
  virtual int fini (void);

  /**
   * Returns 1 before the ACE_Object_Manager has been constructed.
   * This flag can be used to determine if the program is constructing
   * static objects.  If no static object spawns any threads, the
   * program will be single-threaded when this flag returns 1.  (Note
   * that the program still might construct some static objects when
   * this flag returns 0, if ACE_HAS_NONSTATIC_OBJECT_MANAGER is not
   * defined.)
   */
  static int starting_up (void);

  /**
   * Returns 1 after the ACE_Object_Manager has been destroyed.  This
   * flag can be used to determine if the program is in the midst of
   * destroying static objects.  (Note that the program might destroy
   * some static objects before this flag can return 1, if
   * ACE_HAS_NONSTATIC_OBJECT_MANAGER is not defined.)
   */
  static int shutting_down (void);

  /**
   * Register an ACE_Cleanup object for cleanup at process
   * termination.  The object is deleted via the
   * <ace_cleanup_destroyer>.  If you need more flexibility, see the
   * @c other at_exit method below.  For OS's that do not have
   * processes, cleanup takes place at the end of <main>.  Returns 0
   * on success.  On failure, returns -1 and sets errno to: EAGAIN if
   * shutting down, ENOMEM if insufficient virtual memory, or EEXIST
   * if the object (or array) had already been registered.
   */
  static int at_exit (ACE_Cleanup *object, void *param = 0, const char* name = 0);

#if defined (ACE_HAS_TSS_EMULATION)
  static int init_tss (void);
  int init_tss_i (void);
#endif

  /**
   * Register an object (or array) for cleanup at process termination.
   * "cleanup_hook" points to a (global, or static member) function
   * that is called for the object or array when it to be destroyed.
   * It may perform any necessary cleanup specific for that object or
   * its class.  "param" is passed as the second parameter to the
   * @a cleanup_hook function; the first parameter is the object (or
   * array) to be destroyed.  @a cleanup_hook, for example, may delete
   * the object (or array).  For OS's that do not have processes, this
   * function is the same as <at_thread_exit>.  Returns 0 on success.
   * On failure, returns -1 and sets errno to: EAGAIN if shutting
   * down, ENOMEM if insufficient virtual memory, or EEXIST if the
   * object (or array) had already been registered.
   */
  static int at_exit (void *object,
                      ACE_CLEANUP_FUNC cleanup_hook,
                      void *param,
                      const char* name = 0);

  static int remove_at_exit (void *object);

#if 0 /* not implemented yet */
  /// Similar to at_exit(), except that the cleanup_hook is called
  /// when the current thread exits instead of when the program terminates.
  static int at_thread_exit (void *object,
                             ACE_CLEANUP_FUNC cleanup_hook,
                             void *param,
                             const char* name);
#endif /* 0 */

  /// Unique identifiers for preallocated objects.  Please see
  /// ace/Managed_Object.h for information on accessing preallocated
  /// objects.
  enum Preallocated_Object
    {
      ACE_FILECACHE_LOCK,
#if defined (ACE_HAS_THREADS)
      ACE_STATIC_OBJECT_LOCK,
#endif /* ACE_HAS_THREADS */
#if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0)
      ACE_MT_CORBA_HANDLER_LOCK,
      ACE_DUMP_LOCK,
      ACE_SIG_HANDLER_LOCK,
      ACE_SINGLETON_NULL_LOCK,
      ACE_SINGLETON_RECURSIVE_THREAD_LOCK,
      ACE_THREAD_EXIT_LOCK,
#if !defined (ACE_LACKS_ACE_TOKEN)
      ACE_TOKEN_MANAGER_CREATION_LOCK,
      ACE_TOKEN_INVARIANTS_CREATION_LOCK,
#endif /* ! ACE_LACKS_ACE_TOKEN */
      ACE_PROACTOR_EVENT_LOOP_LOCK,
#endif /* ACE_MT_SAFE */

      // Hook for preallocated objects provided by application.
      ACE_APPLICATION_PREALLOCATED_OBJECT_DECLARATIONS

      ACE_PREALLOCATED_OBJECTS  // This enum value must be last!
    };

  /// Unique identifiers for preallocated arrays.  Please see
  /// ace/Managed_Object.h for information on accessing preallocated
  /// arrays.
  enum Preallocated_Array
    {
      /// There currently are no preallocated arrays in the ACE
      /// library.  If the application doesn't have any, make sure
      /// the the preallocated_array size is at least one by declaring
      /// this dummy . . .
      ACE_EMPTY_PREALLOCATED_ARRAY,

      /// Hook for preallocated arrays provided by application.
      ACE_APPLICATION_PREALLOCATED_ARRAY_DECLARATIONS

      ACE_PREALLOCATED_ARRAYS  // This enum value must be last!
    };

  /**
   * @deprecated
   * Accesses a default signal set used, for example,
   * in ACE_Sig_Guard methods.
   * Deprecated: use ACE_Object_Manager::default_mask () instead.
   */
  static ACE_Sig_Set &default_mask (void);

private:
  /// For at_exit support.
  ACE_OS_Exit_Info exit_info_;

#if !defined (ACE_LACKS_ACE_SVCCONF)
  /// Preallocated objects collection.
  ACE_Object_Manager_Preallocations *preallocations_;

  /// ACE_Service_Config signal handler.
  ACE_Sig_Adapter *ace_service_config_sig_handler_;
#endif /* ! ACE_LACKS_ACE_SVCCONF */

  /// Register an object or array for deletion at program termination.
  /// See description of static version above for return values.
  int at_exit_i (void *object, ACE_CLEANUP_FUNC cleanup_hook, void *param, const char* name);

  /// Remove an object for deletion at program termination.
  /// See description of static version above for return values.
  int remove_at_exit_i (void *object);

#if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0)
public:
  // = The <get_singleton_lock> accessors are for internal
  // use by ACE_Singleton _only_.

  /**
   * Accesses an ACE_Null_Mutex to be used for construction of
   * ACE_Singletons.  Returns 0, and the lock in the argument, on
   * success; returns -1 on failure.
   */
  static int get_singleton_lock (ACE_Null_Mutex *&);

  /**
   * Accesses a non-recursive ACE_Thread_Mutex to be used for
   * construction of ACE_Singletons.  Returns 0, and the lock in the
   * argument, on success; returns -1 on failure.
   */
  static int get_singleton_lock (ACE_Thread_Mutex *&);

  /**
   * Accesses a non-recursive ACE_Mutex to be used for construction
   * of ACE_Singletons.  Returns 0, and the lock in the argument, on
   * success; returns -1 on failure.
   */
  static int get_singleton_lock (ACE_Mutex *&);

  /**
   * Accesses a recursive ACE_Recursive_Thread_Mutex to be used for
   * construction of ACE_Singletons.  Returns 0, and the lock in the
   * argument, on success; returns -1 on failure.
   */
  static int get_singleton_lock (ACE_Recursive_Thread_Mutex *&);

  /**
   * Accesses a readers/writer ACE_RW_Thread_Mutex to be used for
   * construction of ACE_Singletons.  Returns 0, and the lock in the
   * argument, on success; returns -1 on failure.
   */
  static int get_singleton_lock (ACE_RW_Thread_Mutex *&);
#endif /* ACE_MT_SAFE */

public:
  // For internal use only by ACE_Managed_Objects.

  /**
   * Accessor to singleton instance.  Because static member functions
   * are provided in the interface, this should not be public.  However,
   * it is public so that ACE_Managed_Object<TYPE> can access it.
   */
  static ACE_Object_Manager *instance (void);

  /// Table of preallocated objects.
  static void *preallocated_object[ACE_PREALLOCATED_OBJECTS];

  /// Table of preallocated arrays.
  static void *preallocated_array[ACE_PREALLOCATED_ARRAYS];

public:
  /// Application code should not use these explicitly, so they're
  /// hidden here.  They're public so that the ACE_Object_Manager can
  /// be constructed/destructed in <main> with
  /// ACE_HAS_NONSTATIC_OBJECT_MANAGER.
  ACE_Object_Manager (void);
  ~ACE_Object_Manager (void);

private:
  /// Singleton pointer.
  static ACE_Object_Manager *instance_;

#if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0)
  /// Lock that is used to guard internal structures.
  ACE_Recursive_Thread_Mutex *internal_lock_;

  /// Null lock for guarding singleton creation.
  ACE_Cleanup_Adapter<ACE_Null_Mutex> *singleton_null_lock_;

  /// Lock for guarding singleton creation, when Object_Manager
  /// hasn't been started up, or has already been shut down.
  ACE_Cleanup_Adapter<ACE_Recursive_Thread_Mutex> *singleton_recursive_lock_;
#endif /* ACE_MT_SAFE */

#if defined (ACE_HAS_TSS_EMULATION)
  /// Main thread's thread-specific storage array.
  void *ts_storage_[ACE_TSS_Emulation::ACE_TSS_THREAD_KEYS_MAX];
  bool ts_storage_initialized_;
#endif /* ACE_HAS_TSS_EMULATION */

#if !defined (ACE_HAS_NONSTATIC_OBJECT_MANAGER)
  friend class ACE_Object_Manager_Manager;
#endif /* ACE_HAS_NONSTATIC_OBJECT_MANAGER */

  /// Disallow copying by not implementing the following . . .
  ACE_Object_Manager (const ACE_Object_Manager &);
  ACE_Object_Manager &operator= (const ACE_Object_Manager &);
};

ACE_END_VERSIONED_NAMESPACE_DECL

#include "ace/Static_Object_Lock.h"

#if defined (__ACE_INLINE__)
#include "ace/Object_Manager.inl"
#endif /* __ACE_INLINE__ */

#include "ace/Managed_Object.h"

#if !defined (ACE_LACKS_ACE_SVCCONF)
// We can't use the ACE_SVC_FACTORY_DECLARE macro here because this
// needs to be in the ACE_Export context rather than the
// ACE_Svc_Export context.
ACE_BEGIN_VERSIONED_NAMESPACE_DECL
class ACE_Service_Object;
ACE_END_VERSIONED_NAMESPACE_DECL
ACE_FACTORY_DECLARE (ACE, ACE_Service_Manager)
#endif /* ! ACE_LACKS_ACE_SVCCONF */


#include /**/ "ace/post.h"
#endif /* ACE_OBJECT_MANAGER_H */
