Hi Steven et al.I would like to suggest some further modifications of the current APIs of libtracefs. The problem that I am trying to solve with this modifications is the unnecessary and potentially confusing variety of patterns used when implementing the APIs for dealing with 'instances', 'kprobes', 'histigrams' and 'synthetic events'. I believe that unifying/templating the structure of those APIs will be beneficial and will make the usage fare more intuitive. I am posting below a pseudo code for one possible implementation of such template APIs that can be used as a starting point for a discussion.
/** * tracefs_XXX_alloc - allocate a new tracefs_XXX descriptor. This only * initializes the descriptor, it does not introduce any changes on the * system. * * @arguments: Some arguments specific for the type of the object ... * * Returns a newly allocated tracefs_XXX descriptor objext, or NULL in case * of an error. The returned instance must be freed by tracefs_XXX_free(). */ struct tracefs_XXX *tracefs_XXX_alloc(arguments); /** * tracefs_XXX_create - creates new tracefs_XXX object on the system. * This method calls tracefs_XXX_alloc() internally. * * @arguments: Some arguments specific for the type of the object ... * This function should not take an instance as argument. Otherwise the * same instance will have to be passed to tracefs_XXX_destroy(), which * can be a problem in some more sophisticated use-cases. * * Returns 0 on succes and -1 on error. On error, errno is set to: * EBUSY - the object already exists on the system. * ENOMEM - memory allocation failure. * ENIVAL - a parameter is passed as NULL or value that should not be or * a problem writing into the system. */ struct tracefs_XXX *tracefs_XXX_create(arguments); /** * tracefs_XXX_find - find a tracefs_XXX object that already exists on the * system. This method calls tracefs_XXX_alloc() internally. * * @arguments: Some arguments specific for the type of the object ... * This function should not take an instance as argument. Otherwise the same * instance will have to be passed to tracefs_XXX_destroy(), which can be a * problem in some more sophisticated use-cases. * * Returns tracefs_XXX descriptor on succes and NULL if the object do not * exist on the system or in the case of an error. On error, errno is set to: * ENOMEM - memory allocation failure. * ENIVAL - a parameter is passed as NULL or value that should not be or * a problem writing into the system. */ struct tracefs_XXX *tracefs_XXX_find(arguments); /** * tracefs_instance_destroy - Remove/clears a tracefs_XXX objext from the * system. tracefs_XXX_free() must be called in order to free the memory used * by the descriptor itself. * * @obj: Pointer to the tracefs_XXX descriptor of the objext to be destroyed. * @force: If false the object is not guaranteed to be destroyed. If @force * is true, all tangled objects that prevent the destruction of the object * will be destroyed as well. * * This function should not take any other arguments. * * Returns -1 in case of an error or if the object failed to destroy. * 0 otherwise. */ int tracefs_XXX_destroy(struct tracefs_XXX *obj, bool force); /** * tracefs_XXX_free - Free a tracefs_XXX descriptor, previously allocated * by tracefs_XXX_alloc, tracefs_XXX_create() or tracefs_XXX_find(). * * @obj: Pointer to the tracefs_XXX descriptor objext to be freed. * * This function should not take any other arguments. */ void tracefs_XXX_free(struct tracefs_XXX *obj); /** * tracefs_XXX_YYY - Method implementing the user action 'YYY' (can be * enable/disable, start/stop/clear, ... etc.) * * @obj: Pointer to the tracefs_XXX objext for witch the user action will * apply. * @instance: Ftrace instance, can be NULL for top tracing instance. * @more_arguments: Some additional arguments specific for the type XXX and * the action YYY. */ void/int tracefs_XXX_YYY(struct tracefs_XXX *obj, struct tracefs_instance *inst, more_arguments); Thanks a lot! Yordan