/
githubmirror
/
rsyslog
Обзор
Документация
Войти
/
githubmirror
/
rsyslog
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
runtime/obj-types.h
434 строки
21 KB
Rainer Gerhards
build: normalize object prototypes and remove decl noise
07 фев 2026, 13:32
Не верифицирован
07 фев 2026, 13:32
63a233a
Код
Авторство
О чём код?
/* Some type definitions and macros for the obj object. * I needed to move them out of the main obj.h, because obj.h's * prototypes use other data types. However, their .h's rely * on some of the obj.h data types and macros. So I needed to break * that loop somehow and I've done that by moving the typedefs * into this file here. * * Copyright 2008-2026 Rainer Gerhards and Adiscon GmbH. * * This file is part of the rsyslog runtime library. * * Licensed 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 * -or- * see COPYING.ASL20 in the source distribution * * 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. */ #ifndef OBJ_TYPES_H_INCLUDED #define OBJ_TYPES_H_INCLUDED #include "stringbuf.h" #include "syslogd-types.h" #include "atomic.h" /* property types for obj[De]Serialize() */ typedef enum { PROPTYPE_NONE = 0, /* currently no value set */ PROPTYPE_PSZ = 1, PROPTYPE_SHORT = 2, PROPTYPE_INT = 3, PROPTYPE_LONG = 4, PROPTYPE_INT64 = 5, PROPTYPE_CSTR = 6, PROPTYPE_SYSLOGTIME = 7 } propType_t; typedef unsigned objID_t; typedef enum { /* IDs of base methods supported by all objects - used for jump table, so * they must start at zero and be incremented. -- rgerhards, 2008-01-04 */ objMethod_CONSTRUCT = 0, objMethod_DESTRUCT = 1, objMethod_SERIALIZE = 2, objMethod_DESERIALIZE = 3, objMethod_SETPROPERTY = 4, objMethod_CONSTRUCTION_FINALIZER = 5, objMethod_GETSEVERITY = 6, objMethod_DEBUGPRINT = 7 } objMethod_t; #define OBJ_NUM_METHODS 8 /* must be updated to contain the max number of methods supported */ /* the base data type for interfaces * This MUST be in sync with the ifBEGIN macro */ struct interface_s { int ifVersion; /* must be set to version requested */ int ifIsLoaded; /* is the interface loaded? (0-no, 1-yes, 2-load failed; if not 1, functions can NOT be called! */ }; struct objInfo_s { uchar *pszID; /* the object ID as a string */ size_t lenID; /* length of the ID string */ int iObjVers; uchar *pszName; rsRetVal (*objMethods[OBJ_NUM_METHODS])(void *, ...); rsRetVal (*QueryIF)(interface_t *); struct modInfo_s *pModInfo; }; struct obj_s { /* the dummy struct that each derived class can be casted to */ objInfo_t *pObjInfo; #ifndef NDEBUG /* this means if debug... */ unsigned int iObjCooCKiE; /* must always be 0xBADEFEE for a valid object */ #endif uchar *pszName; /* the name of *this* specific object instance */ }; /* macros which must be gloablly-visible (because they are used during definition of * other objects. */ #ifndef NDEBUG /* this means if debug... */ #include <string.h> #define BEGINobjInstance obj_t objData #define ISOBJ_assert(pObj) \ do { \ assert((pObj) != NULL); \ assert((unsigned)((obj_t *)(pObj))->iObjCooCKiE == (unsigned)0xBADEFEE); \ } while (0); #define ISOBJ_TYPE_assert(pObj, objType) \ do { \ assert(pObj != NULL); \ if (strcmp((char *)(((obj_t *)pObj)->pObjInfo->pszID), #objType)) { \ dbgprintf( \ "%s:%d ISOBJ assert failure: invalid object type, expected '%s' " \ "actual '%s', cookie: %X\n", \ __FILE__, __LINE__, #objType, (((obj_t *)pObj)->pObjInfo->pszID), ((obj_t *)(pObj))->iObjCooCKiE); \ fprintf(stderr, \ "%s:%d ISOBJ assert failure: invalid object type, expected '%s' " \ "actual '%s', cookie: %X\n", \ __FILE__, __LINE__, #objType, (((obj_t *)pObj)->pObjInfo->pszID), \ ((obj_t *)(pObj))->iObjCooCKiE); \ fflush(stderr); \ assert(!strcmp((char *)(((obj_t *)pObj)->pObjInfo->pszID), #objType)); \ } \ assert((unsigned)((obj_t *)(pObj))->iObjCooCKiE == (unsigned)0xBADEFEE); \ } while (0) /* now the same for pointers to "regular" objects (like wrkrInstanceData) */ #define PTR_ASSERT_DEF unsigned int _Assert_type; #define PTR_ASSERT_SET_TYPE(_ptr, _type) _ptr->_Assert_type = _type #define PTR_ASSERT_CHK(_ptr, _type) \ do { \ assert(_ptr != NULL); \ if (_ptr->_Assert_type != _type) { \ dbgprintf( \ "%s:%d PTR_ASSERT_CHECK failure: invalid pointer type %x, " \ "expected %x\n", \ __FILE__, __LINE__, _ptr->_Assert_type, _type); \ fprintf(stderr, \ "%s:%d PTR_ASSERT_CHECK failure: invalid pointer type %x, " \ "expected %x\n", \ __FILE__, __LINE__, _ptr->_Assert_type, _type); \ assert(_ptr->_Assert_type == _type); \ } \ } while (0) #else /* non-debug mode, no checks but much faster */ #define BEGINobjInstance obj_t objData #define ISOBJ_TYPE_assert(pObj, objType) #define ISOBJ_assert(pObj) #define PTR_ASSERT_DEF #define PTR_ASSERT_SET_TYPE(_ptr, _type) #define PTR_ASSERT_CHK(_ptr, _type) #endif /* a set method for *very simple* object accesses. Note that this does * NOT conform to the standard calling conventions and should be * used only if actually nothing can go wrong! -- rgerhards, 2008-04-17 */ #define DEFpropGetMeth(obj, prop, dataType) \ dataType obj##Get##prop(void) { \ return pThis->prop = pVal; \ } #define DEFpropSetMethPTR(obj, prop, dataType) \ rsRetVal obj##Set##prop(obj##_t *pThis, dataType *pVal) { \ pThis->prop = pVal; \ return RS_RET_OK; \ } #define PROTOTYPEpropSetMethPTR(obj, prop, dataType) rsRetVal obj##Set##prop(obj##_t *pThis, dataType *) #define DEFpropSetMethFP(obj, prop, dataType) \ rsRetVal obj##Set##prop(obj##_t *pThis, dataType) { \ pThis->prop = pVal; \ return RS_RET_OK; \ } #define PROTOTYPEpropSetMethFP(obj, prop, dataType) rsRetVal obj##Set##prop(obj##_t *pThis, dataType) #define DEFpropSetMeth(obj, prop, dataType) \ rsRetVal obj##Set##prop(obj##_t *pThis, dataType pVal) { \ pThis->prop = pVal; \ return RS_RET_OK; \ } #define PROTOTYPEpropSetMeth(obj, prop, dataType) rsRetVal obj##Set##prop(obj##_t *pThis, dataType pVal) #define INTERFACEpropSetMeth(obj, prop, dataType) rsRetVal (*Set##prop)(obj##_t * pThis, dataType) /* class initializer */ #define PROTOTYPEObjClassInit(objName) rsRetVal objName##ClassInit(struct modInfo_s *) /* below: objName must be the object name (e.g. vm, strm, ...) and ISCORE must be * 1 if the module is a statically linked core module and 0 if it is a * dynamically loaded one. -- rgerhards, 2008-02-29 */ #define OBJ_IS_CORE_MODULE 1 /* This should better be renamed to something like "OBJ_IS_NOT_LIBHEAD" or so... ;) */ #define OBJ_IS_LOADABLE_MODULE 0 #define BEGINObjClassInit(objName, objVers, objType) \ rsRetVal objName##ClassInit(struct modInfo_s *pModInfo) { \ DEFiRet; \ if (objType == OBJ_IS_CORE_MODULE) { /* are we a core module? */ \ CHKiRet(objGetObjInterface(&obj)); /* this provides the root pointer for all other queries */ \ } \ CHKiRet(obj.InfoConstruct(&pObjInfoOBJ, (uchar *)#objName, objVers, (rsRetVal(*)(void *))objName##Construct, \ (rsRetVal(*)(void *))objName##Destruct, \ (rsRetVal(*)(interface_t *))objName##QueryInterface, pModInfo)); #define ENDObjClassInit(objName) \ iRet = obj.RegisterObj((uchar *)#objName, pObjInfoOBJ); \ finalize_it: \ RETiRet; \ } /* ... and now the same for abstract classes. * TODO: consolidate the two -- rgerhards, 2008-02-29 */ #define BEGINAbstractObjClassInit(objName, objVers, objType) \ rsRetVal objName##ClassInit(struct modInfo_s *pModInfo) { \ DEFiRet; \ if (objType == OBJ_IS_CORE_MODULE) { /* are we a core module? */ \ CHKiRet(objGetObjInterface(&obj)); /* this provides the root pointer for all other queries */ \ } \ CHKiRet(obj.InfoConstruct(&pObjInfoOBJ, (uchar *)#objName, objVers, NULL, NULL, \ (rsRetVal(*)(interface_t *))objName##QueryInterface, pModInfo)); #define ENDObjClassInit(objName) \ iRet = obj.RegisterObj((uchar *)#objName, pObjInfoOBJ); \ finalize_it: \ RETiRet; \ } /* now come the class exit. This is to be called immediately before the class is * unloaded (actual unload for plugins, program termination for core modules) * gerhards, 2008-03-10 */ #define PROTOTYPEObjClassExit(objName) rsRetVal objName##ClassExit(void) #define BEGINObjClassExit(objName, objType) \ rsRetVal objName##ClassExit(void) { \ DEFiRet; #define CODESTARTObjClassExit(objName) #define ENDObjClassExit(objName) \ iRet = obj.UnregisterObj((uchar *)#objName); \ RETiRet; \ } /* this defines both the constructor and initializer * rgerhards, 2008-01-10 */ #define PROTOTYPEobjConstruct(obj) rsRetVal obj##Construct(obj##_t **ppThis) #define BEGINobjConstruct(obj) \ static rsRetVal obj##Initialize(obj##_t __attribute__((unused)) * pThis) { \ DEFiRet; #define ENDobjConstruct(obj) \ /* use finalize_it: before calling the macro (if you need it)! */ \ RETiRet; \ } \ rsRetVal obj##Construct(obj##_t **ppThis) { \ DEFiRet; \ obj##_t *pThis; \ \ assert(ppThis != NULL); \ \ if ((pThis = (obj##_t *)calloc(1, sizeof(obj##_t))) == NULL) { \ ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY); \ } \ objConstructSetObjInfo(pThis); \ \ obj##Initialize(pThis); \ \ finalize_it: \ OBJCONSTRUCT_CHECK_SUCCESS_AND_CLEANUP \ RETiRet; \ } /* this defines the destructor. The important point is that the base object * destructor is called. The upper-level class shall destruct all of its * properties, but not the instance itself. This is freed here by the * framework (we need an intact pointer because we need to free the * obj_t structures inside it). A pointer to the object pointer must be * parse, because it is re-set to NULL (this, for example, is important in * cancellation handlers). The object pointer is always named pThis. * The object is always freed, even if there is some error while * Cancellation is blocked during destructors, as this could have fatal * side-effects. However, this also means the upper-level object should * not perform any lengthy processing. * IMPORTANT: if the upper level object requires some situations where the * object shall not be destructed (e.g. via reference counting), then * it shall set pThis to NULL, which prevents destruction of the * object. * processing. * rgerhards, 2008-01-30 */ #define PROTOTYPEobjDestruct(OBJ) rsRetVal OBJ##Destruct(OBJ##_t __attribute__((unused)) * *ppThis) /* note: we generate a prototype in any case, as this does not hurt but * many modules otherwise seem to miss one, which generates compiler * warnings. */ #define BEGINobjDestruct(OBJ) \ rsRetVal OBJ##Destruct(OBJ##_t __attribute__((unused)) * *ppThis) { \ DEFiRet; \ OBJ##_t *pThis; #define CODESTARTobjDestruct(OBJ) \ assert(ppThis != NULL); \ pThis = *ppThis; \ ISOBJ_TYPE_assert(pThis, OBJ); /* note: there was a long-time bug in the macro below that lead to *ppThis = NULL * only when the object was actually destructed. I discovered this issue during * introduction of the pRcvFrom property in smsg_t, but it potentially had other * effects, too. I am not sure if some experienced instability resulted from this * bug OR if its fix will cause harm to so-far "correctly" running code. The later * may very well be. Thus I will change it only for the current branch and also * the beta, but not in all old builds. Let's see how things evolve. * rgerhards, 2009-06-30 */ #define ENDobjDestruct(OBJ) \ goto finalize_it; /* prevent compiler warning ;) */ \ /* no more code here! */ \ finalize_it: \ if (pThis != NULL) { \ obj.DestructObjSelf((obj_t *)pThis); \ free(pThis); \ } \ *ppThis = NULL; \ RETiRet; \ } /* this defines the debug print entry point. DebugPrint is optional. If * it is provided, the object should output some meaningful information * via the debug system. * rgerhards, 2008-02-20 */ #define PROTOTYPEObjDebugPrint(obj) rsRetVal obj##DebugPrint(obj##_t *pThis) #define INTERFACEObjDebugPrint(obj) rsRetVal (*DebugPrint)(obj##_t * pThis) #define BEGINobjDebugPrint(obj) \ rsRetVal obj##DebugPrint(obj##_t __attribute__((unused)) * pThis) { \ DEFiRet; #define CODESTARTobjDebugPrint(obj) \ assert(pThis != NULL); \ ISOBJ_TYPE_assert(pThis, obj); #define ENDobjDebugPrint(obj) \ RETiRet; \ } /* ------------------------------ object loader system ------------------------------ * * The following code builds a dynamic object loader system. The * root idea is that all objects are dynamically loadable, * which is necessary to get a clean plug-in interface where every plugin can access * rsyslog's rich object model via simple and quite portable methods. * * To do so, each object defines one or more interfaces. They are essentially structures * with function (method) pointers. Anyone interested in calling an object must first * obtain the interface and can then call through it. * * The interface data type must always be called <obj>_if_t, as this is expected * by the macros. Having consitent naming is also easier for the programmer. By default, * macros create a static variable named like the object in each calling objects * static data block. * * rgerhards, 2008-02-21 (initial implementation), 2008-04-17 (update of this note) */ /* this defines the QueryInterface print entry point. Over time, it should be * present in all objects. */ #define BEGINobjQueryInterface(obj) \ rsRetVal obj##QueryInterface(obj##_if_t *pIf) { \ DEFiRet; #define CODESTARTobjQueryInterface(obj) assert(pIf != NULL); #define ENDobjQueryInterface(obj) \ RETiRet; \ } #define PROTOTYPEObjQueryInterface(obj) rsRetVal obj##QueryInterface(obj##_if_t *pIf) /* the following macros should be used to define interfaces inside the * header files. */ #define BEGINinterface(obj) \ typedef struct obj##_if_s { \ ifBEGIN /* This MUST always be the first interface member */ #define ENDinterface(obj) \ } \ obj##_if_t; /* the following macro is used to get access to an object (not an instance, * just the class itself!). It must be called before any of the object's * methods can be accessed. The MYLIB part is the name of my library, or NULL if * the caller is a core module. Using the right value here is important to get * the reference counting correct (object accesses from the same library must * not be counted because that would cause a library plugin to never unload, as * its ClassExit() entry points are only called if no object is referenced, which * would never happen as the library references itself. * rgerhards, 2008-03-11 */ #define CORE_COMPONENT NULL /* use this to indicate this is a core component */ #define DONT_LOAD_LIB NULL /* do not load a library to obtain object interface (currently same as CORE_COMPONENT) */ #define objUse(objName, FILENAME) obj.UseObj(__FILE__, (uchar *)#objName, (uchar *)FILENAME, (void *)&objName) #define objRelease(objName, FILENAME) obj.ReleaseObj(__FILE__, (uchar *)#objName, (uchar *)FILENAME, (void *)&objName) /* defines data that must always be present at the very begin of the interface structure */ #define ifBEGIN \ int ifVersion; /* must be set to version requested */ \ int ifIsLoaded; /* is the interface loaded? (0-no, 1-yes; if no, functions can NOT be called! */ /* use the following define some place in your static data (suggested right at * the beginning */ #define DEFobjCurrIf(obj) static obj##_if_t obj = {.ifVersion = obj##CURR_IF_VERSION, .ifIsLoaded = 0}; /* define the prototypes for a class - keep signatures behind PROTOTYPE* * macros so interface changes are localized in this file. */ #define PROTOTYPEObjBasic(obj) \ PROTOTYPEObjClassInit(obj); \ PROTOTYPEObjClassExit(obj); \ PROTOTYPEObjQueryInterface(obj) /* use where typed object ctor/dtor declarations are valid in scope */ #define PROTOTYPEObjFull(obj) \ PROTOTYPEObjBasic(obj); \ PROTOTYPEobjConstruct(obj); \ PROTOTYPEobjDestruct(obj) /* legacy alias kept for broad in-tree compatibility */ #define PROTOTYPEObj(obj) PROTOTYPEObjBasic(obj) /* ------------------------------ end object loader system ------------------------------ */ #include "modules.h" #endif /* #ifndef OBJ_TYPES_H_INCLUDED */