.. Licensed to the Apache Software Foundation (ASF) under one or more
   contributor license agreements.  See the NOTICE file distributed
   with this work for additional information regarding copyright
   ownership.  The ASF licenses this file to you under the Apache
   License, Version 2.0 (the "License"); you may not use this file
   except in compliance with the License.  You may obtain a copy of
   the License at

   http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
   implied.  See the License for the specific language governing
   permissions and limitations under the License.

.. include:: ../../../common.defs

.. default-domain:: cpp

TSConfig Functions
******************

Synopsis
========

.. code-block:: cpp

    #include <ts/ts.h>

.. type:: void (*TSConfigDestroyFunc)(void*)
.. function:: unsigned int TSConfigSet(unsigned int id, void * data, TSConfigDestroyFunc funcp)
.. function:: TSConfig TSConfigGet(unsigned int id)
.. function:: void TSConfigRelease(unsigned int id, TSConfig configp)
.. function:: void* TSConfigDataGet(TSConfig configp)

Description
===========

These functions provide a mechanism to safely update configurations for a plugin.

If a plugin stores its configuration in a data structure, updating that structure due to changes in
the configuration file can be dangerous due to the asynchronous nature of plugin callbacks. To avoid
that problem these functions allow a plugin to register a configuration and then later replace it
with another instance without changing the instance in use by plugin callbacks. This works in the
same manner as `shared pointer <https://en.wikipedia.org/wiki/Smart_pointer>`__. When a plugin needs
to access the configuration data, it calls :func:`TSConfigGet` which returns a pointer that will
remain valid until the plugin calls :func:`TSConfigRelease`. The configuration instance is updated
with :func:`TSConfigSet` which will update an internal pointer but will not change any instance in
use via :func:`TSConfigGet`. When the last in use pointer is released, the old configuration is
destructed using the function passed to func:`TSConfigSet`. This handles the overlapping
configuration update case correctly.

Initialization is done with :func:`TSConfigSet`. The :arg:`id` should be zero on the first call.
This will allocate a slot for the configuration, which is returned. Subsequent calls must use this
value. If the :arg:`id` is not zero, that value is returned. In general, the code will look
something like ::

   class Config { ... }; // Configuration data.
   int Config_Id = 0;
   //...
   void ConfigUpdate() {
      Config* cfg = new Config;
      cfg.load(); // load config...
      Config_Id = TSConfigSet(Config_Id, cfg,
         [](void* cfg){delete static_cast<Config*>(config);});
   }
   //...
   PluginInit() {
      // ...
      ConfigUpdate();
      // ...
   }

:code:`Config_Id` is a global variable holding the configuration id, which is updated by the
return value of :func:`TSConfigSet`.

The configuration instance is retrieved with :func:`TSConfigGet`. This returns a wrapper class from
which the configuration can be extracted with :func:`TSConfigDataGet`. The wrapper is used to
release the configuration instance when it is no longer in use. The code in a callback tends to look
like ::

   int callback() {
      auto cfg_ref = TSConfigGet(Config_Id);
      Config* cfg = static_cast<Config*>(TSConfigDataGet(cfg_ref));
      // ... use cfg
      TSConfigRelease(Config_Id, cfg_ref);
   }
