Commit 6699ed71 authored by Tzvetomir Stoyanov's avatar Tzvetomir Stoyanov Committed by Arnaldo Carvalho de Melo
Browse files

tools lib traceevent: Implement a new API, tep_list_events_copy()



Existing API tep_list_events() is not thread safe, it uses the internal
array sort_events to keep cache of the sorted events and reuses it. This
patch implements a new API, tep_list_events_copy(), which allocates new
sorted array each time it is called. It could be used when a sorted
events functionality is needed in thread safe use cases. It is up to the
caller to free the array.

Signed-off-by: default avatarTzvetomir Stoyanov <tstoyanov@vmware.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Link: http://lore.kernel.org/linux-trace-devel/20181218133013.31094-1-tstoyanov@vmware.com
Link: http://lkml.kernel.org/r/20190401164343.117437443@goodmis.org


Signed-off-by: default avatarSteven Rostedt (VMware) <rostedt@goodmis.org>
Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent fed33e90
Loading
Loading
Loading
Loading
+87 −22
Original line number Diff line number Diff line
@@ -5651,32 +5651,26 @@ static int events_system_cmp(const void *a, const void *b)
	return events_id_cmp(a, b);
}

struct tep_event **tep_list_events(struct tep_handle *pevent, enum tep_event_sort_type sort_type)
static struct tep_event **list_events_copy(struct tep_handle *tep)
{
	struct tep_event **events;
	int (*sort)(const void *a, const void *b);

	events = pevent->sort_events;

	if (events && pevent->last_type == sort_type)
		return events;
	if (!tep)
		return NULL;

	if (!events) {
		events = malloc(sizeof(*events) * (pevent->nr_events + 1));
	events = malloc(sizeof(*events) * (tep->nr_events + 1));
	if (!events)
		return NULL;

		memcpy(events, pevent->events, sizeof(*events) * pevent->nr_events);
		events[pevent->nr_events] = NULL;

		pevent->sort_events = events;

		/* the internal events are sorted by id */
		if (sort_type == TEP_EVENT_SORT_ID) {
			pevent->last_type = sort_type;
	memcpy(events, tep->events, sizeof(*events) * tep->nr_events);
	events[tep->nr_events] = NULL;
	return events;
}
	}

static void list_events_sort(struct tep_event **events, int nr_events,
			     enum tep_event_sort_type sort_type)
{
	int (*sort)(const void *a, const void *b);

	switch (sort_type) {
	case TEP_EVENT_SORT_ID:
@@ -5689,11 +5683,82 @@ struct tep_event **tep_list_events(struct tep_handle *pevent, enum tep_event_sor
		sort = events_system_cmp;
		break;
	default:
		sort = NULL;
	}

	if (sort)
		qsort(events, nr_events, sizeof(*events), sort);
}

/**
 * tep_list_events - Get events, sorted by given criteria.
 * @tep: a handle to the tep context
 * @sort_type: desired sort order of the events in the array
 *
 * Returns an array of pointers to all events, sorted by the given
 * @sort_type criteria. The last element of the array is NULL. The returned
 * memory must not be freed, it is managed by the library.
 * The function is not thread safe.
 */
struct tep_event **tep_list_events(struct tep_handle *tep,
				   enum tep_event_sort_type sort_type)
{
	struct tep_event **events;

	if (!tep)
		return NULL;

	events = tep->sort_events;
	if (events && tep->last_type == sort_type)
		return events;

	if (!events) {
		events = list_events_copy(tep);
		if (!events)
			return NULL;

		tep->sort_events = events;

		/* the internal events are sorted by id */
		if (sort_type == TEP_EVENT_SORT_ID) {
			tep->last_type = sort_type;
			return events;
		}
	}

	list_events_sort(events, tep->nr_events, sort_type);
	tep->last_type = sort_type;

	return events;
}


/**
 * tep_list_events_copy - Thread safe version of tep_list_events()
 * @tep: a handle to the tep context
 * @sort_type: desired sort order of the events in the array
 *
 * Returns an array of pointers to all events, sorted by the given
 * @sort_type criteria. The last element of the array is NULL. The returned
 * array is newly allocated inside the function and must be freed by the caller
 */
struct tep_event **tep_list_events_copy(struct tep_handle *tep,
					enum tep_event_sort_type sort_type)
{
	struct tep_event **events;

	if (!tep)
		return NULL;

	events = list_events_copy(tep);
	if (!events)
		return NULL;

	/* the internal events are sorted by id */
	if (sort_type == TEP_EVENT_SORT_ID)
		return events;

	qsort(events, pevent->nr_events, sizeof(*events), sort);
	pevent->last_type = sort_type;
	list_events_sort(events, tep->nr_events, sort_type);

	return events;
}
+4 −1
Original line number Diff line number Diff line
@@ -544,7 +544,10 @@ void tep_event_info(struct trace_seq *s, struct tep_event *event,
int tep_strerror(struct tep_handle *pevent, enum tep_errno errnum,
		 char *buf, size_t buflen);

struct tep_event **tep_list_events(struct tep_handle *pevent, enum tep_event_sort_type);
struct tep_event **tep_list_events(struct tep_handle *tep,
				   enum tep_event_sort_type);
struct tep_event **tep_list_events_copy(struct tep_handle *tep,
					enum tep_event_sort_type);
struct tep_format_field **tep_event_common_fields(struct tep_event *event);
struct tep_format_field **tep_event_fields(struct tep_event *event);