@@ -22,6 +22,14 @@
#define DEBUG_RECORD 0
#endif
+#ifndef __deprecated
+#define __deprecated(msg) __attribute__((deprecated("msg")))
+#endif
+
+#ifndef __te_private
+#define __te_private(msg) __attribute__((deprecated("msg")))
+#endif
+
struct tep_record {
unsigned long long ts;
unsigned long long offset;
@@ -30,16 +38,32 @@ struct tep_record {
int size; /* size of data */
void *data;
int cpu;
- int ref_count;
- int locked; /* Do not free, even if ref_count is zero */
+
+ int ref_count __te_private(use ref/unref instead);
+ int locked __deprecated(do not use);
void *priv;
+
#if DEBUG_RECORD
- struct tep_record *prev;
- struct tep_record *next;
- long alloc_addr;
+ unsigned long alloc_addr; /* Location ref'ing the last time */
+#endif
+
+#ifdef TE_PRIVATE
+ /* These private fields are only valid if priv is pointing to
+ * _priv_alloc. If that is not the case, the API user has not yet
+ * been ported to the new API.
+ * NOTE: Adding new fields does not break ABI/API.
+ */
+ void (*_finalize) (struct tep_record *record);
+ void *_priv_alloc[0];
#endif
};
+
+struct tep_record *tep_record_alloc(int priv_size,
+ void (*finalize) (struct tep_record *record));
+void tep_record_ref(struct tep_record *record);
+void tep_record_unref(struct tep_record *record);
+
/* ----------------------- tep ----------------------- */
struct tep_handle;
@@ -774,8 +798,7 @@ enum tep_loglevel {
};
void tep_set_loglevel(enum tep_loglevel level);
-/* DEPRECATED */
void tep_print_field(struct trace_seq *s, void *data,
- struct tep_format_field *field);
+ struct tep_format_field *field) __deprecated(Use tep_print_field_content instead);
#endif /* _PARSE_EVENTS_H */
@@ -23,9 +23,6 @@ int tep_vprint(const char *name, enum tep_loglevel level,
int __tep_vprint(const char *name, enum tep_loglevel level,
bool print_err, const char *fmt, va_list ap);
-
-#define __deprecated(msg) __attribute__((deprecated("msg")))
-
/* For backward compatibilty, do not use */
int tep_vwarning(const char *name, const char *fmt, va_list ap) __deprecated(Use tep_vprint instead);
void pr_stat(const char *fmt, ...) __deprecated(Use tep_info instead);
@@ -14,6 +14,7 @@
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
+#include <stddef.h>
#include <ctype.h>
#include <errno.h>
#include <stdint.h>
@@ -22,6 +23,10 @@
#include <linux/time64.h>
#include <netinet/in.h>
+
+#define __te_private(msg)
+#define TE_PRIVATE 1
+
#include "event-parse.h"
#include "event-parse-local.h"
@@ -8113,6 +8118,56 @@ int tep_get_ref(struct tep_handle *tep)
return 0;
}
+struct tep_record *tep_record_alloc(int priv_size,
+ void (*finalize) (struct tep_record *record))
+{
+ struct tep_record *res;
+
+ res = malloc(sizeof(*res) + priv_size);
+ if (!res)
+ return NULL;
+
+ memset(res, 0, sizeof(*res) + priv_size);
+ res->ref_count = 1;
+ res->priv = res->_priv_alloc;
+ res->_finalize = finalize;
+
+ return res;
+}
+
+void tep_record_ref(struct tep_record *record)
+{
+ record->ref_count++;
+
+#if DEBUG_RECORD
+ record->alloc_addr = (unsigned long)__builtin_return_address(0);
+#endif
+}
+
+void tep_record_unref(struct tep_record *record)
+{
+ if (record->ref_count <= 0) {
+ tep_warning("Invalid refcount on record %p", record);
+ return;
+ }
+
+ record->ref_count--;
+
+ if (record->ref_count)
+ return;
+
+ if (record->priv != record->_priv_alloc) {
+ tep_warning("Leaking record %p, update user to new allocation API.",
+ record);
+ return;
+ }
+
+ if (record->_finalize)
+ record->_finalize(record);
+
+ free(record);
+}
+
__hidden void free_tep_format_field(struct tep_format_field *field)
{
free(field->type);