.. highlight:: c

Memtypes
========

FRR includes wrappers around ``malloc()`` and ``free()`` that count the number
of objects currently allocated, for each of a defined ``MTYPE``.

To this extent, there are *memory groups* and *memory types*.  Each memory
type must belong to a memory group, this is used just to provide some basic
structure.

Example:

.. code-block:: c
   :caption: mydaemon.h

   DECLARE_MGROUP(MYDAEMON);
   DECLARE_MTYPE(MYNEIGHBOR);

.. code-block:: c
   :caption: mydaemon.c

   DEFINE_MGROUP(      MYDAEMON, "My daemon's memory");
   DEFINE_MTYPE(       MYDAEMON, MYNEIGHBOR,     "Neighbor entry");
   DEFINE_MTYPE_STATIC(MYDAEMON, MYNEIGHBORNAME, "Neighbor name");

   struct neigh *neighbor_new(const char *name)
   {
           struct neigh *n = XMALLOC(MYNEIGHBOR, sizeof(*n));
           n->name = XSTRDUP(MYNEIGHBORNAME, name);
           return n;
   }

   void neighbor_free(struct neigh *n)
   {
           XFREE(MYNEIGHBORNAME, n->name);
           XFREE(MYNEIGHBOR, n);
   }


Definition
----------

.. c:struct:: memtype

   This is the (internal) type used for MTYPE definitions.  The macros below
   should be used to create these, but in some cases it is useful to pass a
   ``struct memtype *`` pointer to some helper function.

   The ``MTYPE_name`` created by the macros is declared as a pointer, i.e.
   a function taking a ``struct memtype *`` argument can be called with an
   ``MTYPE_name`` argument (as opposed to ``&MTYPE_name``.)

   .. note::

      As ``MTYPE_name`` is a variable assigned from ``&_mt_name`` and not a
      constant expression, it cannot be used as initializer for static
      variables. In the case please fall back to ``&_mt_name``.

.. c:macro:: DECLARE_MGROUP(name)

   This macro forward-declares a memory group and should be placed in a
   ``.h`` file.  It expands to an ``extern struct memgroup`` statement.

.. c:macro:: DEFINE_MGROUP(mname, description)

   Defines/implements a memory group.  Must be placed into exactly one ``.c``
   file (multiple inclusion will result in a link-time symbol conflict).

   Contains additional logic (constructor and destructor) to register the
   memory group in a global list.

.. c:macro:: DECLARE_MTYPE(name)

   Forward-declares a memory type and makes ``MTYPE_name`` available for use.
   Note that the ``MTYPE_`` prefix must not be included in the name, it is
   automatically prefixed.

   ``MTYPE_name`` is created as a `static const` symbol, i.e. a compile-time
   constant.  It refers to an ``extern struct memtype _mt_name``, where `name`
   is replaced with the actual name.

.. c:macro:: DEFINE_MTYPE(group, name, description)

   Define/implement a memory type, must be placed into exactly one ``.c``
   file (multiple inclusion will result in a link-time symbol conflict).

   Like ``DEFINE_MGROUP``, this contains actual code to register the MTYPE
   under its group.

.. c:macro:: DEFINE_MTYPE_STATIC(group, name, description)

   Same as ``DEFINE_MTYPE``, but the ``DEFINE_MTYPE_STATIC`` variant places
   the C ``static`` keyword on the definition, restricting the MTYPE's
   availability to the current source file.  This should be appropriate in
   >80% of cases.

   .. todo::

      Daemons currently have ``daemon_memory.[ch]`` files listing all of
      their MTYPEs.  This is not how it should be, most of these types
      should be moved into the appropriate files where they are used.
      Only a few MTYPEs should remain non-static after that.


Usage
-----

.. c:function:: void *XMALLOC(struct memtype *mtype, size_t size)

.. c:function:: void *XCALLOC(struct memtype *mtype, size_t size)

.. c:function:: void *XSTRDUP(struct memtype *mtype, const char *name)

   Allocation wrappers for malloc/calloc/realloc/strdup, taking an extra
   mtype parameter.

.. c:function:: void *XREALLOC(struct memtype *mtype, void *ptr, size_t size)

   Wrapper around realloc() with MTYPE tracking.  Note that ``ptr`` may
   be NULL, in which case the function does the same as XMALLOC (regardless
   of whether the system realloc() supports this.)

.. c:function:: void XFREE(struct memtype *mtype, void *ptr)

   Wrapper around free(), again taking an extra mtype parameter.  This is
   actually a macro, with the following additional properties:

   - the macro contains ``ptr = NULL``
   - if ptr is NULL, no operation is performed (as is guaranteed by system
     implementations.)  Do not surround XFREE with ``if (ptr != NULL)``
     checks.

.. c:function:: void XCOUNTFREE(struct memtype *mtype, void *ptr)

   This macro is used to count the ``ptr`` as freed without actually freeing
   it. This may be needed in some very specific cases, for example, when the
   ``ptr`` was allocated using any of the above wrappers and will be freed
   by some external library using simple ``free()``.
