spice-common/common/agent_interface.h
Frediano Ziglio b843d02a1b Avoid usage of GCC extension for __VA_ARGS__ where possible
The "##" before __VA_ARGS__ is a GCC extension.
Try to limit its usage where necessary.

Signed-off-by: Frediano Ziglio <freddy77@gmail.com>
Acked-by: Uri Lublin <uril@redhat.com>
2020-08-10 09:55:27 +01:00

565 lines
24 KiB
C++

#pragma once
// *****************************************************************************
// This software is licensed under the GNU Lesser General Public License v2+
// (C) 2017-2019, Christophe de Dinechin <christophe@dinechin.org>
// *****************************************************************************
// This file was part of Recorder
//
// Recorder is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 2 of the License, or
// (at your option) any later version.
//
// Recorder is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with Recorder, in a file named COPYING.
// If not, see <https://www.gnu.org/licenses/>.
// *****************************************************************************
/* This file is based on Recorder's recorder.h file, that describes a general-
* purpose instrumentation interface. agent_interface.h is a trimmed-down
* version of it. */
#include <stdarg.h>
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
static inline void
recorder_dump_on_common_signals(unsigned add, unsigned remove)
{
}
// ============================================================================
//
// Recorder data structures
//
// ============================================================================
typedef struct recorder_entry
/// ---------------------------------------------------------------------------
/// Entry in the flight recorder.
///----------------------------------------------------------------------------
/// Notice that the arguments are stored as "intptr_t" because that type
/// is guaranteed to be the same size as a pointer. This allows us to
/// properly align recorder entries to powers of 2 for efficiency.
/// Also read explanations of \ref _recorder_double and \ref _recorder_float
/// below regarding how to use floating-point with the recorder.
{
const char *format; ///< Printf-style format for record + file/line
uintptr_t timestamp; ///< Time at which record took place
const char *where; ///< Source code function
uintptr_t args[4]; ///< Four arguments, for a total of 8 fields
} recorder_entry;
/// A global counter indicating the order of entries across recorders.
/// this is incremented atomically for each record() call.
/// It must be exposed because all XYZ_record() implementations need to
/// touch the same shared variable in order to provide a global order.
extern uintptr_t recorder_order;
typedef struct recorder_info
///----------------------------------------------------------------------------
/// A linked list of the activated recorders
///----------------------------------------------------------------------------
{
intptr_t trace; ///< Trace this recorder
const char * name; ///< Name of this parameter / recorder
const char * description;///< Description of what is recorded
recorder_entry data[0]; ///< Data for this recorder
} recorder_info;
// ============================================================================
//
// Adding data to a recorder
//
// ============================================================================
extern void recorder_append(recorder_info *rec,
const char *where,
const char *format,
uintptr_t a0,
uintptr_t a1,
uintptr_t a2,
uintptr_t a3);
extern void recorder_append2(recorder_info *rec,
const char *where,
const char *format,
uintptr_t a0,
uintptr_t a1,
uintptr_t a2,
uintptr_t a3,
uintptr_t a4,
uintptr_t a5,
uintptr_t a6,
uintptr_t a7);
extern void recorder_append3(recorder_info *rec,
const char *where,
const char *format,
uintptr_t a0,
uintptr_t a1,
uintptr_t a2,
uintptr_t a3,
uintptr_t a4,
uintptr_t a5,
uintptr_t a6,
uintptr_t a7,
uintptr_t a8,
uintptr_t a9,
uintptr_t a10,
uintptr_t a11);
/// Activate a recorder (during construction time)
extern void recorder_activate(recorder_info *recorder);
// ============================================================================
//
// Declaration of recorders and tweaks
//
// ============================================================================
#define RECORDER_DECLARE(Name) \
/* ----------------------------------------------------------------*/ \
/* Declare a recorder with the given name (for use in headers) */ \
/* ----------------------------------------------------------------*/ \
extern recorder_info * const recorder_info_ptr_for_##Name; \
extern struct recorder_info_for_##Name recorder_info_for_##Name
// ============================================================================
//
// Definition of recorders and tweaks
//
// ============================================================================
#define RECORDER(Name, Size, Info) RECORDER_DEFINE(Name,Size,Info)
#define RECORDER_DEFINE(Name, Size, Info) \
/*!----------------------------------------------------------------*/ \
/*! Define a recorder type with Size elements */ \
/*!----------------------------------------------------------------*/ \
/*! \param Name is the C name fo the recorder. \
*! \param Size is the number of entries in the circular buffer. \
*! \param Info is a description of the recorder for help. */ \
\
/* The entry in linked list for this type */ \
struct recorder_info_for_##Name \
{ \
recorder_info info; \
recorder_entry data[Size]; \
} \
recorder_info_for_##Name = \
{ \
{ \
0, #Name, Info, {} \
}, \
{} \
}; \
recorder_info * const recorder_info_ptr_for_##Name = \
&recorder_info_for_##Name.info; \
\
RECORDER_CONSTRUCTOR \
static void recorder_activate_##Name(void) \
/* ----------------------------------------------------------------*/ \
/* Activate recorder before entering main() */ \
/* ----------------------------------------------------------------*/ \
{ \
recorder_activate(RECORDER_INFO(Name)); \
} \
\
/* Purposefully generate compile error if macro not followed by ; */ \
extern void recorder_activate(recorder_info *recorder)
typedef struct SpiceDummyTweak {
intptr_t tweak_value;
} SpiceDummyTweak;
typedef struct SpiceEmptyStruct {
char dummy[0];
} SpiceEmptyStruct;
#define RECORDER_TWEAK_DECLARE(rec) \
extern const SpiceDummyTweak spice_recorder_tweak_ ## rec
#define RECORDER_TWEAK_DEFINE(rec, value, comment) \
const SpiceDummyTweak spice_recorder_tweak_ ## rec = { (value) }
#define RECORDER_TWEAK(rec) \
((spice_recorder_tweak_ ## rec).tweak_value)
#define RECORDER_TRACE(rec) \
(sizeof(struct recorder_info_for_ ## rec) != sizeof(SpiceEmptyStruct))
// ============================================================================
//
// Access to recorder and tweak info
//
// ============================================================================
#define RECORDER_INFO(Name) (recorder_info_ptr_for_##Name)
// ============================================================================
//
// Recording stuff
//
// ============================================================================
#define record(Name, ...) RECORD_MACRO(Name, __VA_ARGS__)
#define RECORD(Name,...) RECORD_MACRO(Name, __VA_ARGS__)
#define RECORD_MACRO(Name, ...) \
RECORD_(RECORD,RECORD_COUNT_(__VA_ARGS__),Name,__VA_ARGS__)
#define RECORD_(RECORD,RCOUNT,Name,...) \
RECORD__(RECORD,RCOUNT,Name,__VA_ARGS__)
#define RECORD__(RECORD,RCOUNT,Name,...) \
RECORD##RCOUNT(Name,__VA_ARGS__)
#define RECORD_COUNT_(...) RECORD_COUNT__(Dummy,##__VA_ARGS__,_X,_X,_12,_11,_10,_9,_8,_7,_6,_5,_4,_3,_2,_1,_0)
#define RECORD_COUNT__(Dummy,_0,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_N,...) _N
#define RECORD_0(Name, Format) \
recorder_append(RECORDER_INFO(Name), \
RECORDER_SOURCE_FUNCTION, \
RECORDER_SOURCE_LOCATION \
Format, 0, 0, 0, 0)
#define RECORD_1(Name, Format, a) \
recorder_append(RECORDER_INFO(Name), \
RECORDER_SOURCE_FUNCTION, \
RECORDER_SOURCE_LOCATION \
Format, \
RECORDER_ARG(a), 0, 0, 0)
#define RECORD_2(Name, Format, a,b) \
recorder_append(RECORDER_INFO(Name), \
RECORDER_SOURCE_FUNCTION, \
RECORDER_SOURCE_LOCATION \
Format, \
RECORDER_ARG(a), \
RECORDER_ARG(b), 0, 0)
#define RECORD_3(Name, Format, a,b,c) \
recorder_append(RECORDER_INFO(Name), \
RECORDER_SOURCE_FUNCTION, \
RECORDER_SOURCE_LOCATION \
Format, \
RECORDER_ARG(a), \
RECORDER_ARG(b), \
RECORDER_ARG(c), 0)
#define RECORD_4(Name, Format, a,b,c,d) \
recorder_append(RECORDER_INFO(Name), \
RECORDER_SOURCE_FUNCTION, \
RECORDER_SOURCE_LOCATION \
Format, \
RECORDER_ARG(a), \
RECORDER_ARG(b), \
RECORDER_ARG(c), \
RECORDER_ARG(d))
#define RECORD_5(Name, Format, a,b,c,d,e) \
recorder_append2(RECORDER_INFO(Name), \
RECORDER_SOURCE_FUNCTION, \
RECORDER_SOURCE_LOCATION \
Format, \
RECORDER_ARG(a), \
RECORDER_ARG(b), \
RECORDER_ARG(c), \
RECORDER_ARG(d), \
RECORDER_ARG(e), 0, 0, 0)
#define RECORD_6(Name, Format, a,b,c,d,e,f) \
recorder_append2(RECORDER_INFO(Name), \
RECORDER_SOURCE_FUNCTION, \
RECORDER_SOURCE_LOCATION \
Format, \
RECORDER_ARG(a), \
RECORDER_ARG(b), \
RECORDER_ARG(c), \
RECORDER_ARG(d), \
RECORDER_ARG(e), \
RECORDER_ARG(f), 0, 0)
#define RECORD_7(Name, Format, a,b,c,d,e,f,g) \
recorder_append2(RECORDER_INFO(Name), \
RECORDER_SOURCE_FUNCTION, \
RECORDER_SOURCE_LOCATION \
Format, \
RECORDER_ARG(a), \
RECORDER_ARG(b), \
RECORDER_ARG(c), \
RECORDER_ARG(d), \
RECORDER_ARG(e), \
RECORDER_ARG(f), \
RECORDER_ARG(g), 0)
#define RECORD_8(Name, Format, a,b,c,d,e,f,g,h) \
recorder_append2(RECORDER_INFO(Name), \
RECORDER_SOURCE_FUNCTION, \
RECORDER_SOURCE_LOCATION \
Format, \
RECORDER_ARG(a), \
RECORDER_ARG(b), \
RECORDER_ARG(c), \
RECORDER_ARG(d), \
RECORDER_ARG(e), \
RECORDER_ARG(f), \
RECORDER_ARG(g), \
RECORDER_ARG(h))
#define RECORD_9(Name, Format, a,b,c,d,e,f,g,h,i) \
recorder_append3(RECORDER_INFO(Name), \
RECORDER_SOURCE_FUNCTION, \
RECORDER_SOURCE_LOCATION \
Format, \
RECORDER_ARG(a), \
RECORDER_ARG(b), \
RECORDER_ARG(c), \
RECORDER_ARG(d), \
RECORDER_ARG(e), \
RECORDER_ARG(f), \
RECORDER_ARG(g), \
RECORDER_ARG(h), \
RECORDER_ARG(i), 0,0,0)
#define RECORD_10(Name, Format, a,b,c,d,e,f,g,h,i,j) \
recorder_append3(RECORDER_INFO(Name), \
RECORDER_SOURCE_FUNCTION, \
RECORDER_SOURCE_LOCATION \
Format, \
RECORDER_ARG(a), \
RECORDER_ARG(b), \
RECORDER_ARG(c), \
RECORDER_ARG(d), \
RECORDER_ARG(e), \
RECORDER_ARG(f), \
RECORDER_ARG(g), \
RECORDER_ARG(h), \
RECORDER_ARG(i), \
RECORDER_ARG(j), 0,0)
#define RECORD_11(Name, Format, a,b,c,d,e,f,g,h,i,j,k) \
recorder_append3(RECORDER_INFO(Name), \
RECORDER_SOURCE_FUNCTION, \
RECORDER_SOURCE_LOCATION \
Format, \
RECORDER_ARG(a), \
RECORDER_ARG(b), \
RECORDER_ARG(c), \
RECORDER_ARG(d), \
RECORDER_ARG(e), \
RECORDER_ARG(f), \
RECORDER_ARG(g), \
RECORDER_ARG(h), \
RECORDER_ARG(i), \
RECORDER_ARG(j), \
RECORDER_ARG(k),0)
#define RECORD_12(Name,Format,a,b,c,d,e,f,g,h,i,j,k,l) \
recorder_append3(RECORDER_INFO(Name), \
RECORDER_SOURCE_FUNCTION, \
RECORDER_SOURCE_LOCATION \
Format, \
RECORDER_ARG(a), \
RECORDER_ARG(b), \
RECORDER_ARG(c), \
RECORDER_ARG(d), \
RECORDER_ARG(e), \
RECORDER_ARG(f), \
RECORDER_ARG(g), \
RECORDER_ARG(h), \
RECORDER_ARG(i), \
RECORDER_ARG(j), \
RECORDER_ARG(k), \
RECORDER_ARG(l))
#define RECORD_X(Name, ...) RECORD_TOO_MANY_ARGS(printf(__VA_ARGS__))
// Some ugly macro drudgery to make things easy to use. Adjust type.
#ifdef __cplusplus
#define RECORDER_ARG(arg) _recorder_arg(arg)
#else // !__cplusplus
#if defined(__GNUC__) && !defined(__clang__)
# if __GNUC__ <= 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 9)
# define RECORDER_WITHOUT_GENERIC
# endif
#endif // __GNUC__
#ifdef RECORDER_WITHOUT_GENERIC
#define RECORDER_ARG(arg) ((uintptr_t) (arg))
#else // !RECORDER_WITHOUT_GENERIC
#define RECORDER_ARG(arg) \
_Generic(arg, \
unsigned char: _recorder_unsigned, \
unsigned short: _recorder_unsigned, \
unsigned: _recorder_unsigned, \
unsigned long: _recorder_unsigned, \
unsigned long long:_recorder_unsigned, \
char: _recorder_char, \
signed char: _recorder_signed, \
signed short: _recorder_signed, \
signed: _recorder_signed, \
signed long: _recorder_signed, \
signed long long: _recorder_signed, \
float: _recorder_float, \
double: _recorder_double, \
default: _recorder_pointer)(arg)
#endif // RECORDER_WITHOUT_GENERIC
#endif // __cplusplus
// ============================================================================
//
// Timing information
//
// ============================================================================
#define RECORD_TIMING_BEGIN(rec) \
do { RECORD(rec, "begin");
#define RECORD_TIMING_END(rec, op, name, value) \
RECORD(rec, "end" op name); \
} while (0)
// ============================================================================
//
// Support macros
//
// ============================================================================
#define RECORDER_SOURCE_FUNCTION __func__ /* Works in C99 and C++11 */
#define RECORDER_SOURCE_LOCATION __FILE__ ":" RECORDER_STRING(__LINE__) ":"
#define RECORDER_STRING(LINE) RECORDER_STRING_(LINE)
#define RECORDER_STRING_(LINE) #LINE
#ifdef __GNUC__
#define RECORDER_CONSTRUCTOR __attribute__((constructor))
#else
#define RECORDER_CONSTRUCTOR
#endif
#ifdef __cplusplus
}
#endif // __cplusplus
// ============================================================================
//
// Utility: Convert floating point values for vararg format
//
// ============================================================================
//
// The recorder stores only uintptr_t in recorder entries. Integer types
// are promoted, pointer types are converted. Floating point values
// are converted a floating point type of the same size as uintptr_t,
// i.e. float are converted to double on 64-bit platforms, and conversely.
#ifdef __cplusplus
#include <string>
// In C++, we don't use _Generic but actual overloading
template <class inttype>
static inline uintptr_t _recorder_arg(inttype i)
{
return (uintptr_t) i;
}
static inline uintptr_t _recorder_arg(const std::string &arg)
{
return (uintptr_t) arg.c_str();
}
#define _recorder_float _recorder_arg
#define _recorder_double _recorder_arg
#else // !__cplusplus
static inline uintptr_t _recorder_char(char c)
// ----------------------------------------------------------------------------
// Necessary because of the way generic selections work
// ----------------------------------------------------------------------------
{
return c;
}
static inline uintptr_t _recorder_unsigned(uintptr_t i)
// ----------------------------------------------------------------------------
// Necessary because of the way generic selections work
// ----------------------------------------------------------------------------
{
return i;
}
static inline uintptr_t _recorder_signed(intptr_t i)
// ----------------------------------------------------------------------------
// Necessary because of the way generic selections work
// ----------------------------------------------------------------------------
{
return (uintptr_t) i;
}
static inline uintptr_t _recorder_pointer(const void *i)
// ----------------------------------------------------------------------------
// Necessary because of the way generic selections work
// ----------------------------------------------------------------------------
{
return (uintptr_t) i;
}
#endif // __cplusplus
static inline uintptr_t _recorder_float(float f)
// ----------------------------------------------------------------------------
// Convert floating point number to intptr_t representation for recorder
// ----------------------------------------------------------------------------
{
if (sizeof(float) == sizeof(intptr_t)) {
union { float f; uintptr_t i; } u;
u.f = f;
return u.i;
} else {
union { double d; uintptr_t i; } u;
u.d = (double) f;
return u.i;
}
}
static inline uintptr_t _recorder_double(double d)
// ----------------------------------------------------------------------------
// Convert double-precision floating point number to intptr_t representation
// ----------------------------------------------------------------------------
{
if (sizeof(double) == sizeof(intptr_t)) {
union { double d; uintptr_t i; } u;
u.d = d;
return u.i;
} else {
// Better to lose precision than not store any data
union { float f; uintptr_t i; } u;
u.f = d;
return u.i;
}
}
// ============================================================================
// Agent-Interface specific definitions
// ============================================================================
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
// launch the Agent-Interface server socket
extern void agent_interface_start(unsigned int port);
//
typedef void (*forward_quality_cb_t)(void *, const char *);
extern void agent_interface_set_forward_quality_cb(forward_quality_cb_t cb, void *data);
// set a callback function triggered when a new client connects to the socket
typedef int (*on_connect_cb_t)(void *);
extern void agent_interface_set_on_connect_cb(on_connect_cb_t cb, void *data);
#ifdef __cplusplus
}
#endif // __cplusplus