General documentation updates 66/8566/5
authorChris Luke <chrisy@flirble.org>
Wed, 27 Sep 2017 19:09:48 +0000 (15:09 -0400)
committerFlorin Coras <florin.coras@gmail.com>
Thu, 28 Sep 2017 01:04:56 +0000 (01:04 +0000)
- We now have several developer-focused docs, so create an index page
  for them.
- Rework several docs to fit into the index structure.
- Experiment with code highlighting; tweak the CSS slightly to make
  it slightly nicer to look at.

Change-Id: I4185a18f84fa0764745ca7a3148276064a3155c6
Signed-off-by: Chris Luke <chrisy@flirble.org>
16 files changed:
README.md
doxygen/Makefile
doxygen/assets/doxy-vpp.css
doxygen/dev_doc.md [new file with mode: 0644]
doxygen/doxygen.cfg
doxygen/test_framework_doc.md
doxygen/user_doc.md
extras/libmemif/docs/buildinstructions_doc.md [moved from extras/libmemif/docs/BuildInstructions.md with 85% similarity]
extras/libmemif/docs/gettingstarted_doc.md [moved from extras/libmemif/docs/GettingStarted.md with 95% similarity]
extras/libmemif/examples/README.md [deleted file]
extras/libmemif/examples/example_setup_doc.md [moved from extras/libmemif/examples/ExampleSetup.md with 96% similarity]
extras/libmemif/examples/examples_doc.md [new file with mode: 0644]
extras/libmemif/libmemif_doc.md [moved from extras/libmemif/README.md with 83% similarity]
src/plugins/acl/acl_hash_lookup_doc.md [moved from src/plugins/acl/hash_lookup.md with 99% similarity]
src/plugins/acl/acl_multicore_doc.md [moved from src/plugins/acl/acl-plugin.md with 99% similarity]
src/vlibapi/api_doc.md

index 596494b..090dd35 100644 (file)
--- a/README.md
+++ b/README.md
@@ -30,10 +30,11 @@ Directory name         | Description
      build-root        | Build output directory
      doxygen           | Documentation generator configuration
      dpdk              | DPDK patches and build infrastructure
-@ref src               | VPP source code
+@ref extras/libmemif   | Client library for memif
+@ref src/examples      | VPP example code
 @ref src/plugins       | VPP bundled plugins directory
 @ref src/svm           | Shared virtual memory allocation library
-     src/tests         | Unit tests
+     src/tests         | Standalone tests (not part of test harness)
      src/vat           | VPP API test program
 @ref src/vlib          | VPP application library
 @ref src/vlibapi       | VPP API library
@@ -43,9 +44,8 @@ Directory name         | Description
 @ref src/vpp           | VPP application
 @ref src/vpp-api       | VPP application API bindings
 @ref src/vppinfra      | VPP core library
-     test              | Unit tests
 @ref src/vpp/api       | Not-yet-relocated API bindings
-@ref src/examples      | VPP example code
+     test              | Unit tests and Python test harness
 
 ## Getting started
 
@@ -95,12 +95,13 @@ for this can be found [on the Setting up Vagrant wiki page]
 ## More information
 
 Several modules provide documentation, see @subpage user_doc for more
-information.
+end-user-oriented information. Also see @subpage dev_doc for developer notes.
 
 Visit the [VPP wiki](https://wiki.fd.io/view/VPP) for details on more
-advanced building strategies and development notes.
+advanced building strategies and other development notes.
 
 
 ## Test Framework
 
-There is PyDoc generated documentation available for the VPP test framework. See @subpage test_framework_doc for details.
+There is PyDoc generated documentation available for the VPP test framework.
+See @ref test_framework_doc for details.
index b6ba588..5870530 100644 (file)
@@ -62,7 +62,8 @@ DOXY_INPUT ?= \
        $(wildcard $(WS_ROOT)/*.md) \
        $(wildcard $(DOXY_DIR)/*.md) \
        $(DOXY_SRC_DIRECTORIES) \
-       $(DOXY_SRC)/plugins
+       $(DOXY_SRC)/plugins \
+       extras
 
 # Strip leading workspace path from input names
 DOXY_INPUT := $(subst $(WS_ROOT)/,,$(DOXY_INPUT))
@@ -73,7 +74,6 @@ DOXY_INPUT := $(subst $(WS_ROOT)/,,$(DOXY_INPUT))
 # there's a DPDK equivalent that conflicts.
 # These must be left-anchored paths for the regexp below to work.
 DOXY_EXCLUDE ?= \
-       $(DOXY_SRC)/vlib/buffer.c \
        $(DOXY_SRC)/vpp-api/lua
 
 # Generate a regexp for filenames to exclude
index 3b74eb6..108600a 100644 (file)
@@ -45,3 +45,9 @@ pre {
 a.el {
        font-family: Consolas, Courier, monospace;
 }
+
+div.fragment {
+       padding: 2px;
+       margin-left: 8px;
+}
+
diff --git a/doxygen/dev_doc.md b/doxygen/dev_doc.md
new file mode 100644 (file)
index 0000000..d1d22f7
--- /dev/null
@@ -0,0 +1,12 @@
+Developer Documentation    {#dev_doc}
+=======================
+
+Programming notes for developers.
+
+- @subpage test_framework_doc
+- @subpage sample_plugin_doc
+- @subpage api_doc
+- @subpage vapi_doc
+- @subpage acl_hash_lookup
+- @subpage acl_multicore
+- @subpage libmemif_doc
index 7675b69..f2d3911 100644 (file)
@@ -882,7 +882,8 @@ EXAMPLE_RECURSIVE      = NO
 # that contain images that are to be included in the documentation (see the
 # \image command).
 
-IMAGE_PATH             = $(ROOT)/doxygen/assets
+IMAGE_PATH             = $(ROOT)/doxygen/assets \
+                         $(ROOT)/extras/libmemif/docs
 
 # The INPUT_FILTER tag can be used to specify a program that doxygen should
 # invoke to filter for each input file. Doxygen will invoke the filter program
index b2873c5..755a29e 100644 (file)
@@ -3,5 +3,6 @@ Test Framework Documentation    {#test_framework_doc}
 
 PyDoc generated documentation for the "make test" framework is available for the following releases
 
+- [Test framework documentation for VPP 17.10](https://docs.fd.io/vpp/17.10/vpp_make_test/html)
 - [Test framework documentation for VPP 17.04](https://docs.fd.io/vpp/17.04/vpp_make_test/html)
 - [Test framework documentation for VPP 17.01](https://docs.fd.io/vpp/17.01/vpp_make_test/html)
index 65b09f9..f7d7936 100644 (file)
@@ -16,6 +16,4 @@ Several modules provide operational, dataplane-user focused documentation.
 - @subpage span_doc
 - @subpage srv6_doc
 - @subpage srmpls_doc
-- @subpage sample_plugin_doc
 - @subpage nat64_doc
-- @subpage api_doc
similarity index 85%
rename from extras/libmemif/docs/BuildInstructions.md
rename to extras/libmemif/docs/buildinstructions_doc.md
index 9bb59b9..838e835 100644 (file)
@@ -1,4 +1,4 @@
-## Build Instructions
+## Build Instructions    {#libmemif_build_doc}
 
 Install dependencies
 ```
@@ -49,6 +49,7 @@ commands:
        ip-set <index> <ip-addr> - set interface ip address
        rx-mode <index> <qid> <polling|interrupt> - set queue rx mode
 ```
+
 #### Examples
 
-Once the library is build/installed, refer to [Examples](../examples/README.md) and [Getting started](GettingStarted.md) for additional information on basic use cases and API usage.
+Once the library is built/installed, refer to @ref libmemif_examples_doc and @ref libmemif_gettingstarted_doc for additional information on basic use cases and API usage.
similarity index 95%
rename from extras/libmemif/docs/GettingStarted.md
rename to extras/libmemif/docs/gettingstarted_doc.md
index 3cc0ceb..e3ae6e5 100644 (file)
@@ -1,8 +1,8 @@
-## Getting started
+## Getting started    {#libmemif_gettingstarted_doc}
 
 #### Concept (Connecting to VPP)
 
-For detailed information on api calls and structures please refer to [libmemif.h](../src/libmemif.h)
+For detailed information on api calls and structures please refer to @ref libmemif.h.
 
 1. Initialize memif
    - Declare callback function handling file descriptor event polling.
@@ -152,7 +152,8 @@ if (err != MEMIF_ERR_SUCCESS)
 
 #### Example app (libmemif fd event polling):
 
-- [ICMP Responder](../examples/icmp_responder/main.c)
+- @ref extras/libmemif/examples/icmp_responder
+
 > Optional argument: transmit queue id.
 ```
 icmpr 1
@@ -162,11 +163,14 @@ icmpr 1
 
 #### Example app:
 
-- [ICMP Responder custom fd event polling](../examples/icmp_responder-epoll/main.c)
+ICMP Responder custom fd event polling.
+
+- @ref extras/libmemif/examples/icmp_responder-epoll
 
 #### Example app (multi-thread queue polling)
 
-- [ICMP Responder multi-thread](../examples/icmp_responder-mt/main.c)
+ICMP Responder multi-thread.
+- @ref extras/libmemif/examples/icmp_responder-mt
 
 > Simple example of libmemif multi-thread usage. Connection establishment is handled by main thread. There are two rx queues in this example. One in polling mode and second in interrupt mode.
 
diff --git a/extras/libmemif/examples/README.md b/extras/libmemif/examples/README.md
deleted file mode 100644 (file)
index 1375d27..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-## Examples
-
-After build, root folder will contain scripts linking binary examples with library (same name as example apps). These scripts can be executed to run example apps without installing the library. Example apps binaries can be found in _libs_ filder. To run binaries directly, make sure that libmemif library is installed.
-
-#### Run in container
-ligato/libmemif-sample-service image contains built and installed libmemf. To run different examples, override docker CMD to start container in bash:
-```
-# docker run -it --entrypoint=/bin/bash -i --rm --name icmp-responder --hostname icmp-responder --privileged -v "/run/vpp/:/run/vpp/" ligato/libmemif-sample-service
-```
-Current WORKDIR is set to root repository directory. Example apps can be run from this directory (a script linking binary with library), or browse to ./.libs folder and execute binary directly.
-
-Example app | Description
-------------|------------
-[icmpr](../examples/icmp_responder/main.c) | Simplest implementaion. Event polling is handled by libmemif. Single memif conenction in slave mode is created (id 0). Use Ctrl + C to exit app. Memif receive mode: interrupt.
-[icmpr-epoll](../examples/icmp_responder-epoll/main.c) (run in container by default) | Supports multiple connections and master mode. User can create/delete connections, set ip addresses, print connection information. [Example setup](ExampleSetup.md) contains instructions on basic connection use cases setups. Memif receive mode: interrupt. App provides functionality to disable interrupts for specified queue/s for testing purposes. Polling mode is not implemented in this example.
-[icmpr-mt](../examples/icmp_responder-mt/main.c) | Multi-thread example, very similar to icmpr-epoll. Packets are handled in threads assigned to specific queues. Slave mode only. Memif receive mode: polling (memif_rx_poll function), interrupt (memif_rx_interrupt function). Receive modes differ per queue.
similarity index 96%
rename from extras/libmemif/examples/ExampleSetup.md
rename to extras/libmemif/examples/example_setup_doc.md
index a02506d..89a0b10 100644 (file)
@@ -1,11 +1,12 @@
-## Example setup
+## Example setup    {#libmemif_example_setup_doc}
 
 #### VPP-memif master icmp_responder slave
 
-> Libmemif example app(s) use memif default socket file: /run/vpp/memif.sock.
+> Libmemif example app(s) use memif default socket file: `/run/vpp/memif.sock`.
 
 Run VPP and icmpr-epoll example (default example when running in container).
-> Other examples work similar to icmpr-epoll. Brief explanation can be found in [Examples readme](README.md) file.
+
+> Other examples work similar to icmpr-epoll. Brief explanation can be found in @ref libmemif_examples_doc .
 
 VPP-side config:
 ```
diff --git a/extras/libmemif/examples/examples_doc.md b/extras/libmemif/examples/examples_doc.md
new file mode 100644 (file)
index 0000000..11937c5
--- /dev/null
@@ -0,0 +1,18 @@
+## Examples    {#libmemif_examples_doc}
+
+After build, root folder will contain scripts linking binary examples with library (same name as example apps). These scripts can be executed to run example apps without installing the library. Example apps binaries can be found in _libs_ filder. To run binaries directly, make sure that libmemif library is installed.
+
+#### Run in container
+
+`ligato/libmemif-sample-service` image contains built and installed libmemf. To run different examples, override docker CMD to start container in bash:
+
+```
+# docker run -it --entrypoint=/bin/bash -i --rm --name icmp-responder --hostname icmp-responder --privileged -v "/run/vpp/:/run/vpp/" ligato/libmemif-sample-service
+```
+Current WORKDIR is set to root repository directory. Example apps can be run from this directory (a script linking binary with library), or browse to `./.libs` folder and execute binary directly.
+
+Example app | Description
+------------|------------
+@ref extras/libmemif/examples/icmp_responder | Simplest implementaion. Event polling is handled by libmemif. Single memif conenction in slave mode is created (id 0). Use Ctrl + C to exit app. Memif receive mode: interrupt.
+@ref extras/libmemif/examples/icmp_responder-epoll (run in container by default) | Supports multiple connections and master mode. User can create/delete connections, set ip addresses, print connection information. @ref libmemif_example_setup_doc contains instructions on basic connection use cases setups. Memif receive mode: interrupt. App provides functionality to disable interrupts for specified queue/s for testing purposes. Polling mode is not implemented in this example.
+@ref extras/libmemif/examples/icmp_responder-mt) | Multi-thread example, very similar to icmpr-epoll. Packets are handled in threads assigned to specific queues. Slave mode only. Memif receive mode: polling (memif_rx_poll function), interrupt (memif_rx_interrupt function). Receive modes differ per queue.
similarity index 83%
rename from extras/libmemif/README.md
rename to extras/libmemif/libmemif_doc.md
index 0cccfb3..fb4a18a 100644 (file)
@@ -1,5 +1,6 @@
-Shared Memory Packet Interface (memif) Library
+Shared Memory Packet Interface (memif) Library    {#libmemif_doc}
 ==============================================
+
 ## Introduction
 
 Shared memory packet interface (memif) provides high performance packet transmit and receive between user application and Vector Packet Processing (VPP) or multiple user applications. Using libmemif, user application can create shared memory interface in master or slave mode and connect to VPP or another application using libmemif. Once the connection is established, user application can receive or transmit packets using libmemif API.
@@ -63,10 +64,11 @@ commands:
        rx-mode <index> <qid> <polling|interrupt> - set queue rx mode
 ```
 
-Continue with [Example setup](examples/ExampleSetup.md) which contains instructions on how to set up conenction between icmpr-epoll example app and VPP-memif.
+Continue with @ref libmemif_example_setup which contains instructions on how to set up conenction between icmpr-epoll example app and VPP-memif.
 
 #### Next steps
 
-- [Build instructions](docs/BuildInstructions.md) Instructions on how to build/install libmemif.
-- [Examples](examples/README.md) More example apps presenting different features.
-- [Getting started](docs/GettingStarted.md) Introduction to libmemif API. Explaining library usage in custom app.
+- @subpage libmemif_build_doc
+- @subpage libmemif_examples_doc
+- @subpage libmemif_example_setup_doc
+- @subpage libmemif_gettingstarted_doc
similarity index 99%
rename from src/plugins/acl/hash_lookup.md
rename to src/plugins/acl/acl_hash_lookup_doc.md
index 9552464..cb93df0 100644 (file)
@@ -1,4 +1,4 @@
-ACL plugin constant-time lookup design
+ACL plugin constant-time lookup design    {#acl_hash_lookup}
 ======================================
 
 The initial implementation of ACL plugin performs a trivial for() cycle,
similarity index 99%
rename from src/plugins/acl/acl-plugin.md
rename to src/plugins/acl/acl_multicore_doc.md
index 1b44bca..b2cf7b9 100644 (file)
@@ -1,4 +1,4 @@
-Multicore support for ACL plugin
+Multicore support for ACL plugin    {#acl_multicore}
 ================================
 
 This captures some considerations and design decisions that I have made,
@@ -20,16 +20,18 @@ at the time of replacing the old ACL being checked, with
 the new ACL.
 
 In case an acl_add_replace is being used to replace the rules
-within the existing entry, a reallocation of am->acls[X].rules
+within the existing entry, a reallocation of `am->acls[X].rules`
 vector will happen and potentially a change in count.
 
 acl_match_5tuple() has the following code:
 
+```{.c}
   a = am->acls + acl_index;
   for (i = 0; i < a->count; i++)
     {
       r = a->rules + i;
      . . .
+```
 
 Ideally we should be immune from a->rules changing,
 but the problem arises if the count changes in flight,
index e620ee1..2e7ae09 100644 (file)
@@ -6,12 +6,12 @@ APIs.
 
 Messages are defined in `*.api` files. Today, there are about 50 api files,
 with more arriving as folks add programmable features.  The API file compiler
-sources reside in @ref src/tools/vppapigen .
+sources reside in @ref src/tools/vppapigen.
 
-Here's a typical request/response message definition, from
-@ref src/vnet/interface.api :
+From @ref src/vnet/interface.api, here's a typical request/response message
+definition:
 
-```
+```{.c}
      autoreply define sw_interface_set_flags
      {
        u32 client_index;
@@ -22,10 +22,10 @@ Here's a typical request/response message definition, from
      };
 ```
 
-To a first approximation, the API compiler renders this definition  as
-follows:
+To a first approximation, the API compiler renders this definition into
+`build-root/.../vpp/include/vnet/interface.api.h` as follows:
 
-```
+```{.c}
     /****** Message ID / handler enum ******/
     #ifdef vl_msg_id
     vl_msg_id(VL_API_SW_INTERFACE_SET_FLAGS, vl_api_sw_interface_set_flags_t_handler)
@@ -60,10 +60,13 @@ follows:
         u32 context;
         i32 retval;
     }) vl_api_sw_interface_set_flags_reply_t;
+
+    ...
+    #endif /* vl_typedefs */
 ```
 
 To change the admin state of an interface, a binary api client sends a
-@ref vl_api_sw_interface_set_flags_t to vpp, which will respond  with a
+@ref vl_api_sw_interface_set_flags_t to VPP, which will respond  with a
 @ref vl_api_sw_interface_set_flags_reply_t message.
 
 Multiple layers of software, transport types, and shared libraries
@@ -76,7 +79,7 @@ implement a variety of features:
   message handlers.
     
 Correctly-coded message handlers know nothing about the transport used to
-deliver messages to/from vpp. It's reasonably straighforward to use multiple
+deliver messages to/from VPP. It's reasonably straighforward to use multiple
 API message transport types simultaneously.
 
 For historical reasons, binary api messages are (putatively) sent in network
@@ -90,12 +93,12 @@ Since binary API messages are always processed in order, we allocate messages
 using a ring allocator whenever possible. This scheme is extremely fast when
 compared with a traditional memory allocator, and doesn't cause heap
 fragmentation. See
-@ref src/vlibmemory/memory_shared.c @ref vl_msg_api_alloc_internal() .
+@ref src/vlibmemory/memory_shared.c @ref vl_msg_api_alloc_internal().
 
 Regardless of transport, binary api messages always follow a @ref msgbuf_t
 header:
 
-```
+```{.c}
     typedef struct msgbuf_
     {
       unix_shared_memory_queue_t *q;
@@ -109,7 +112,7 @@ This structure makes it easy to trace messages without having to
 decode them - simply save data_len bytes - and allows
 @ref vl_msg_api_free() to rapidly dispose of message buffers:
 
-```
+```{.c}
     void
     vl_msg_api_free (void *a)
     {
@@ -130,34 +133,34 @@ decode them - simply save data_len bytes - and allows
           return;
         }
       <snip>
-     }
+    }
 ```
 
 ## Message Tracing and Replay
 
-It's extremely important that vpp can capture and replay sizeable binary API
+It's extremely important that VPP can capture and replay sizeable binary API
 traces. System-level issues involving hundreds of thousands of API
 transactions can be re-run in a second or less. Partial replay allows one to
 binary-search for the point where the wheels fall off. One can add scaffolding
 to the data plane, to trigger when complex conditions obtain.
 
 With binary API trace, print, and replay, system-level bug reports of the form
-"after 300,000 API transactions, the vpp data-plane stopped forwarding
+"after 300,000 API transactions, the VPP data-plane stopped forwarding
 traffic, FIX IT!" can be solved offline.
 
 More often than not, one discovers that a control-plane client
 misprograms the data plane after a long time or under complex
 circumstances. Without direct evidence, "it's a data-plane problem!"
 
-See @ref src/vlibmemory/memory_vlib.c @ref vl_msg_api_process_file() ,
-and @ref src/vlibapi/api_shared.c . See also the debug CLI command "api trace"
+See @ref src/vlibmemory/memory_vlib.c @ref vl_msg_api_process_file(),
+and @ref src/vlibapi/api_shared.c. See also the debug CLI command "api trace"
 
 ## Client connection details
 
-Establishing a binary API connection to vpp from a C-language client
+Establishing a binary API connection to VPP from a C-language client
 is easy:
 
-```
+```{.c}
         int
         connect_to_vpe (char *client_name, int client_message_queue_length)
         {
@@ -176,9 +179,9 @@ is easy:
         }       
 ```
 
-32 is a typical value for client_message_queue_length. Vpp cannot
+32 is a typical value for client_message_queue_length. VPP cannot
 block when it needs to send an API message to a binary API client, and
-the vpp-side binary API message handlers are very fast. When sending
+the VPP-side binary API message handlers are very fast. When sending
 asynchronous messages, make sure to scrape the binary API rx ring with
 some enthusiasm.
 
@@ -187,7 +190,7 @@ some enthusiasm.
 Calling @ref vl_client_connect_to_vlib spins up a binary API message RX
 pthread:
 
-```
+```{.c}
         static void *
         rx_thread_fn (void *arg)
         {
@@ -214,31 +217,31 @@ To handle the binary API message queue yourself, use
 @ref vl_client_connect_to_vlib_no_rx_pthread.
 
 In turn, vl_msg_api_queue_handler(...) uses mutex/condvar signalling
-to wake up, process vpp -> client traffic, then sleep. Vpp supplies a
-condvar broadcast when the vpp -> client API message queue transitions
+to wake up, process VPP -> client traffic, then sleep. VPP supplies a
+condvar broadcast when the VPP -> client API message queue transitions
 from empty to nonempty.
 
-Vpp checks its own binary API input queue at a very high rate.  Vpp
+VPP checks its own binary API input queue at a very high rate.  VPP
 invokes message handlers in "process" context [aka cooperative
 multitasking thread context] at a variable rate, depending on
 data-plane packet processing requirements.
 
 ## Client disconnection details
 
-To disconnect from vpp, call @ref vl_client_disconnect_from_vlib
-Please arrange to call this function if the client application
-terminates abnormally. Vpp makes every effort to hold a decent funeral
-for dead clients, but vpp can't guarantee to free leaked memory in the
+To disconnect from VPP, call @ref vl_client_disconnect_from_vlib.
+Please arrange to call this function if the client application
+terminates abnormally. VPP makes every effort to hold a decent funeral
+for dead clients, but VPP can't guarantee to free leaked memory in the
 shared binary API segment.
 
-## Sending binary API messages to vpp
+## Sending binary API messages to VPP
 
-The point of the exercise is to send binary API messages to vpp, and
-to receive replies from vpp. Many vpp binary APIs comprise a client
+The point of the exercise is to send binary API messages to VPP, and
+to receive replies from VPP. Many VPP binary APIs comprise a client
 request message, and a simple status reply. For example, to
 set the admin status of an interface, one codes:
 
-```
+```{.c}
     vl_api_sw_interface_set_flags_t *mp;
 
     mp = vl_msg_api_alloc (sizeof (*mp));
@@ -262,9 +265,9 @@ Key points:
   network byte order
 
 * The client-library global data structure @ref api_main keeps track
-  of sufficient pointers and handles used to communicate with vpp
+  of sufficient pointers and handles used to communicate with VPP
 
-## Receiving binary API messages from vpp
+## Receiving binary API messages from VPP
 
 Unless you've made other arrangements (see @ref
 vl_client_connect_to_vlib_no_rx_pthread), *messages are received on a
@@ -273,7 +276,7 @@ thread is the responsibility of the application!
 
 Set up message handlers about as follows:
 
-```
+```{.c}
     #define vl_typedefs                /* define message structures */
     #include <vpp/api/vpe_all_api_h.h>
     #undef vl_typedefs
@@ -319,7 +322,7 @@ vectors in the @ref api_main_t structure. As of this writing: not all
 vector element values can be set through the API. You'll see sporadic
 API message registrations followed by minor adjustments of this form:
 
-```
+```{.c}
     /*
      * Thread-safe API messages
      */