Topics

RFC: Kernel's Object Tracing API

Cruz Alcaraz, Juan M <juan.m.cruz.alcaraz@...>
 

Zephyr kernel provides debug hooks to allow debugging tools to access nanokernel and microkernel objects (FIFO, LIFO, semaphores, etc.) and display their attributes for content inspection.

Background
=========

The current implementation of zephyr declares, inside each nanokernel structure, a "next" field that allows to access the objects as a simple linked list:
Example:
struct nano_fifo {
union {
struct _nano_queue wait_q;
struct _nano_queue data_q;
};
int stat;
#ifdef CONFIG_DEBUG_TRACING_KERNEL_OBJECTS
struct nano_fifo *next;
#endif
};

Each kernel object has a global pointer to the first object of the linked list. Each pointer can be used by a debug tool as a handler to allow it to iterate over each data structure.
E.g.
struct nano_sem *_track_list_nano_sem;
struct nano_fifo *_track_list_nano_fifo;
struct nano_lifo *_track_list_nano_lifo;
struct nano_timer *_track_list_nano_timer;

The current implementation has the following issues:

- The handlers are buried inside the kernel implementation

- There is no documentation on how they can be used to implement object inspection.

- The implementation does not have a clear pattern that a developer can follow to extend the functionality (e.g. add new kernel objects to the tracing hooks)

Proposal
=======
The following is a proposal of a public API that will give the following improvements to the current implementation without modifying the gist of the original implementation.

- The API is published as a header file in the public API directory (/include)

- The API will propose a clear pattern to follow to extend the scope of the tracing functionality in the future.

- The API is easily documented through Doxygen and it can be added as a section in the Zephyr Kernel Primer.

The API will be defined in the header file: include/misc/object_traicing.h
The API will implement the following macros:

DECLARE_TRACE_LIST(name)
Declares a list of traceable objects with a particular name.
This macro declares the global pointer to the first element of the list.
The elements are of an existing type _debg_obj_<name> and the pointer will have the unique name _trace_list_<name>

DEBUG_TRACING_OBJ_INIT(name, obj)
Adds the object "obj" to the list "name". This macro will be used by the kernel when an specific object is created. After creation, the object is added in the linked list.

DEBUG_TRACING_HEAD(name)
Gives the access to the first element of the trace list "name"

DEBUG_TRACING_NEXT(name, obj)
Gives access to the contiguous element of the element "obj" in the trace list "name"

Typedef data type aliases are needed to homologate the kernel object's types and allow a macro to relate them whit the list pointers.
These typedefs would only be used on debugger mode and when the CONFIG_DEBUG_TRACING_KERNEL_OBJECTS is active.

The following code is an example of how the implementation could follow:

typedef struct nano_sem _dbg_obj_nano_sem;
typedef struct nano_fifo _dbg_obj_nano_fifo;
typedef struct nano_lifo _dbg_obj_nano_lifo;
typedef struct nano_timer _dbg_obj_nano_timer;
typedef struct pool_struct _ dbg_obj_micro_mem_pool;

#define DECLARE_TRACE_LIST(name) type *_trace_list_##name

#define DEBUG_TRACING_HEAD(name) ((_dbg_obj_##name *)_trace_list##name)

#define DEBUG_TRACING_NEXT(name, obj) (((_dbg_obj_##name *)obj)->next)

#define DEBUG_TRACING_OBJ_INIT(name, obj) { \
_dbg_obj_##name *temp = _trace_list_##name; \
_trace_list_##name = obj; \
obj->next = temp

All comments are welcome :)