162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci#include <errno.h>
362306a36Sopenharmony_ci#include <inttypes.h>
462306a36Sopenharmony_ci#include <linux/list.h>
562306a36Sopenharmony_ci#include <linux/compiler.h>
662306a36Sopenharmony_ci#include <linux/string.h>
762306a36Sopenharmony_ci#include "ordered-events.h"
862306a36Sopenharmony_ci#include "session.h"
962306a36Sopenharmony_ci#include "asm/bug.h"
1062306a36Sopenharmony_ci#include "debug.h"
1162306a36Sopenharmony_ci#include "ui/progress.h"
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#define pr_N(n, fmt, ...) \
1462306a36Sopenharmony_ci	eprintf(n, debug_ordered_events, fmt, ##__VA_ARGS__)
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#define pr(fmt, ...) pr_N(1, pr_fmt(fmt), ##__VA_ARGS__)
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_cistatic void queue_event(struct ordered_events *oe, struct ordered_event *new)
1962306a36Sopenharmony_ci{
2062306a36Sopenharmony_ci	struct ordered_event *last = oe->last;
2162306a36Sopenharmony_ci	u64 timestamp = new->timestamp;
2262306a36Sopenharmony_ci	struct list_head *p;
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci	++oe->nr_events;
2562306a36Sopenharmony_ci	oe->last = new;
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci	pr_oe_time2(timestamp, "queue_event nr_events %u\n", oe->nr_events);
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci	if (!last) {
3062306a36Sopenharmony_ci		list_add(&new->list, &oe->events);
3162306a36Sopenharmony_ci		oe->max_timestamp = timestamp;
3262306a36Sopenharmony_ci		return;
3362306a36Sopenharmony_ci	}
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci	/*
3662306a36Sopenharmony_ci	 * last event might point to some random place in the list as it's
3762306a36Sopenharmony_ci	 * the last queued event. We expect that the new event is close to
3862306a36Sopenharmony_ci	 * this.
3962306a36Sopenharmony_ci	 */
4062306a36Sopenharmony_ci	if (last->timestamp <= timestamp) {
4162306a36Sopenharmony_ci		while (last->timestamp <= timestamp) {
4262306a36Sopenharmony_ci			p = last->list.next;
4362306a36Sopenharmony_ci			if (p == &oe->events) {
4462306a36Sopenharmony_ci				list_add_tail(&new->list, &oe->events);
4562306a36Sopenharmony_ci				oe->max_timestamp = timestamp;
4662306a36Sopenharmony_ci				return;
4762306a36Sopenharmony_ci			}
4862306a36Sopenharmony_ci			last = list_entry(p, struct ordered_event, list);
4962306a36Sopenharmony_ci		}
5062306a36Sopenharmony_ci		list_add_tail(&new->list, &last->list);
5162306a36Sopenharmony_ci	} else {
5262306a36Sopenharmony_ci		while (last->timestamp > timestamp) {
5362306a36Sopenharmony_ci			p = last->list.prev;
5462306a36Sopenharmony_ci			if (p == &oe->events) {
5562306a36Sopenharmony_ci				list_add(&new->list, &oe->events);
5662306a36Sopenharmony_ci				return;
5762306a36Sopenharmony_ci			}
5862306a36Sopenharmony_ci			last = list_entry(p, struct ordered_event, list);
5962306a36Sopenharmony_ci		}
6062306a36Sopenharmony_ci		list_add(&new->list, &last->list);
6162306a36Sopenharmony_ci	}
6262306a36Sopenharmony_ci}
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_cistatic union perf_event *__dup_event(struct ordered_events *oe,
6562306a36Sopenharmony_ci				     union perf_event *event)
6662306a36Sopenharmony_ci{
6762306a36Sopenharmony_ci	union perf_event *new_event = NULL;
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	if (oe->cur_alloc_size < oe->max_alloc_size) {
7062306a36Sopenharmony_ci		new_event = memdup(event, event->header.size);
7162306a36Sopenharmony_ci		if (new_event)
7262306a36Sopenharmony_ci			oe->cur_alloc_size += event->header.size;
7362306a36Sopenharmony_ci	}
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	return new_event;
7662306a36Sopenharmony_ci}
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_cistatic union perf_event *dup_event(struct ordered_events *oe,
7962306a36Sopenharmony_ci				   union perf_event *event)
8062306a36Sopenharmony_ci{
8162306a36Sopenharmony_ci	return oe->copy_on_queue ? __dup_event(oe, event) : event;
8262306a36Sopenharmony_ci}
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_cistatic void __free_dup_event(struct ordered_events *oe, union perf_event *event)
8562306a36Sopenharmony_ci{
8662306a36Sopenharmony_ci	if (event) {
8762306a36Sopenharmony_ci		oe->cur_alloc_size -= event->header.size;
8862306a36Sopenharmony_ci		free(event);
8962306a36Sopenharmony_ci	}
9062306a36Sopenharmony_ci}
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_cistatic void free_dup_event(struct ordered_events *oe, union perf_event *event)
9362306a36Sopenharmony_ci{
9462306a36Sopenharmony_ci	if (oe->copy_on_queue)
9562306a36Sopenharmony_ci		__free_dup_event(oe, event);
9662306a36Sopenharmony_ci}
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci#define MAX_SAMPLE_BUFFER	(64 * 1024 / sizeof(struct ordered_event))
9962306a36Sopenharmony_cistatic struct ordered_event *alloc_event(struct ordered_events *oe,
10062306a36Sopenharmony_ci					 union perf_event *event)
10162306a36Sopenharmony_ci{
10262306a36Sopenharmony_ci	struct list_head *cache = &oe->cache;
10362306a36Sopenharmony_ci	struct ordered_event *new = NULL;
10462306a36Sopenharmony_ci	union perf_event *new_event;
10562306a36Sopenharmony_ci	size_t size;
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	new_event = dup_event(oe, event);
10862306a36Sopenharmony_ci	if (!new_event)
10962306a36Sopenharmony_ci		return NULL;
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	/*
11262306a36Sopenharmony_ci	 * We maintain the following scheme of buffers for ordered
11362306a36Sopenharmony_ci	 * event allocation:
11462306a36Sopenharmony_ci	 *
11562306a36Sopenharmony_ci	 *   to_free list -> buffer1 (64K)
11662306a36Sopenharmony_ci	 *                   buffer2 (64K)
11762306a36Sopenharmony_ci	 *                   ...
11862306a36Sopenharmony_ci	 *
11962306a36Sopenharmony_ci	 * Each buffer keeps an array of ordered events objects:
12062306a36Sopenharmony_ci	 *    buffer -> event[0]
12162306a36Sopenharmony_ci	 *              event[1]
12262306a36Sopenharmony_ci	 *              ...
12362306a36Sopenharmony_ci	 *
12462306a36Sopenharmony_ci	 * Each allocated ordered event is linked to one of
12562306a36Sopenharmony_ci	 * following lists:
12662306a36Sopenharmony_ci	 *   - time ordered list 'events'
12762306a36Sopenharmony_ci	 *   - list of currently removed events 'cache'
12862306a36Sopenharmony_ci	 *
12962306a36Sopenharmony_ci	 * Allocation of the ordered event uses the following order
13062306a36Sopenharmony_ci	 * to get the memory:
13162306a36Sopenharmony_ci	 *   - use recently removed object from 'cache' list
13262306a36Sopenharmony_ci	 *   - use available object in current allocation buffer
13362306a36Sopenharmony_ci	 *   - allocate new buffer if the current buffer is full
13462306a36Sopenharmony_ci	 *
13562306a36Sopenharmony_ci	 * Removal of ordered event object moves it from events to
13662306a36Sopenharmony_ci	 * the cache list.
13762306a36Sopenharmony_ci	 */
13862306a36Sopenharmony_ci	size = sizeof(*oe->buffer) + MAX_SAMPLE_BUFFER * sizeof(*new);
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	if (!list_empty(cache)) {
14162306a36Sopenharmony_ci		new = list_entry(cache->next, struct ordered_event, list);
14262306a36Sopenharmony_ci		list_del_init(&new->list);
14362306a36Sopenharmony_ci	} else if (oe->buffer) {
14462306a36Sopenharmony_ci		new = &oe->buffer->event[oe->buffer_idx];
14562306a36Sopenharmony_ci		if (++oe->buffer_idx == MAX_SAMPLE_BUFFER)
14662306a36Sopenharmony_ci			oe->buffer = NULL;
14762306a36Sopenharmony_ci	} else if ((oe->cur_alloc_size + size) < oe->max_alloc_size) {
14862306a36Sopenharmony_ci		oe->buffer = malloc(size);
14962306a36Sopenharmony_ci		if (!oe->buffer) {
15062306a36Sopenharmony_ci			free_dup_event(oe, new_event);
15162306a36Sopenharmony_ci			return NULL;
15262306a36Sopenharmony_ci		}
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci		pr("alloc size %" PRIu64 "B (+%zu), max %" PRIu64 "B\n",
15562306a36Sopenharmony_ci		   oe->cur_alloc_size, size, oe->max_alloc_size);
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci		oe->cur_alloc_size += size;
15862306a36Sopenharmony_ci		list_add(&oe->buffer->list, &oe->to_free);
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci		oe->buffer_idx = 1;
16162306a36Sopenharmony_ci		new = &oe->buffer->event[0];
16262306a36Sopenharmony_ci	} else {
16362306a36Sopenharmony_ci		pr("allocation limit reached %" PRIu64 "B\n", oe->max_alloc_size);
16462306a36Sopenharmony_ci		return NULL;
16562306a36Sopenharmony_ci	}
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	new->event = new_event;
16862306a36Sopenharmony_ci	return new;
16962306a36Sopenharmony_ci}
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_cistatic struct ordered_event *
17262306a36Sopenharmony_ciordered_events__new_event(struct ordered_events *oe, u64 timestamp,
17362306a36Sopenharmony_ci		    union perf_event *event)
17462306a36Sopenharmony_ci{
17562306a36Sopenharmony_ci	struct ordered_event *new;
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	new = alloc_event(oe, event);
17862306a36Sopenharmony_ci	if (new) {
17962306a36Sopenharmony_ci		new->timestamp = timestamp;
18062306a36Sopenharmony_ci		queue_event(oe, new);
18162306a36Sopenharmony_ci	}
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	return new;
18462306a36Sopenharmony_ci}
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_civoid ordered_events__delete(struct ordered_events *oe, struct ordered_event *event)
18762306a36Sopenharmony_ci{
18862306a36Sopenharmony_ci	list_move(&event->list, &oe->cache);
18962306a36Sopenharmony_ci	oe->nr_events--;
19062306a36Sopenharmony_ci	free_dup_event(oe, event->event);
19162306a36Sopenharmony_ci	event->event = NULL;
19262306a36Sopenharmony_ci}
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ciint ordered_events__queue(struct ordered_events *oe, union perf_event *event,
19562306a36Sopenharmony_ci			  u64 timestamp, u64 file_offset, const char *file_path)
19662306a36Sopenharmony_ci{
19762306a36Sopenharmony_ci	struct ordered_event *oevent;
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	if (!timestamp || timestamp == ~0ULL)
20062306a36Sopenharmony_ci		return -ETIME;
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	if (timestamp < oe->last_flush) {
20362306a36Sopenharmony_ci		pr_oe_time(timestamp,      "out of order event\n");
20462306a36Sopenharmony_ci		pr_oe_time(oe->last_flush, "last flush, last_flush_type %d\n",
20562306a36Sopenharmony_ci			   oe->last_flush_type);
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci		oe->nr_unordered_events++;
20862306a36Sopenharmony_ci	}
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	oevent = ordered_events__new_event(oe, timestamp, event);
21162306a36Sopenharmony_ci	if (!oevent) {
21262306a36Sopenharmony_ci		ordered_events__flush(oe, OE_FLUSH__HALF);
21362306a36Sopenharmony_ci		oevent = ordered_events__new_event(oe, timestamp, event);
21462306a36Sopenharmony_ci	}
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	if (!oevent)
21762306a36Sopenharmony_ci		return -ENOMEM;
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	oevent->file_offset = file_offset;
22062306a36Sopenharmony_ci	oevent->file_path = file_path;
22162306a36Sopenharmony_ci	return 0;
22262306a36Sopenharmony_ci}
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_cistatic int do_flush(struct ordered_events *oe, bool show_progress)
22562306a36Sopenharmony_ci{
22662306a36Sopenharmony_ci	struct list_head *head = &oe->events;
22762306a36Sopenharmony_ci	struct ordered_event *tmp, *iter;
22862306a36Sopenharmony_ci	u64 limit = oe->next_flush;
22962306a36Sopenharmony_ci	u64 last_ts = oe->last ? oe->last->timestamp : 0ULL;
23062306a36Sopenharmony_ci	struct ui_progress prog;
23162306a36Sopenharmony_ci	int ret;
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	if (!limit)
23462306a36Sopenharmony_ci		return 0;
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	if (show_progress)
23762306a36Sopenharmony_ci		ui_progress__init(&prog, oe->nr_events, "Processing time ordered events...");
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	list_for_each_entry_safe(iter, tmp, head, list) {
24062306a36Sopenharmony_ci		if (session_done())
24162306a36Sopenharmony_ci			return 0;
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci		if (iter->timestamp > limit)
24462306a36Sopenharmony_ci			break;
24562306a36Sopenharmony_ci		ret = oe->deliver(oe, iter);
24662306a36Sopenharmony_ci		if (ret)
24762306a36Sopenharmony_ci			return ret;
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci		ordered_events__delete(oe, iter);
25062306a36Sopenharmony_ci		oe->last_flush = iter->timestamp;
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci		if (show_progress)
25362306a36Sopenharmony_ci			ui_progress__update(&prog, 1);
25462306a36Sopenharmony_ci	}
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	if (list_empty(head))
25762306a36Sopenharmony_ci		oe->last = NULL;
25862306a36Sopenharmony_ci	else if (last_ts <= limit)
25962306a36Sopenharmony_ci		oe->last = list_entry(head->prev, struct ordered_event, list);
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	if (show_progress)
26262306a36Sopenharmony_ci		ui_progress__finish();
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	return 0;
26562306a36Sopenharmony_ci}
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_cistatic int __ordered_events__flush(struct ordered_events *oe, enum oe_flush how,
26862306a36Sopenharmony_ci				   u64 timestamp)
26962306a36Sopenharmony_ci{
27062306a36Sopenharmony_ci	static const char * const str[] = {
27162306a36Sopenharmony_ci		"NONE",
27262306a36Sopenharmony_ci		"FINAL",
27362306a36Sopenharmony_ci		"ROUND",
27462306a36Sopenharmony_ci		"HALF ",
27562306a36Sopenharmony_ci		"TOP  ",
27662306a36Sopenharmony_ci		"TIME ",
27762306a36Sopenharmony_ci	};
27862306a36Sopenharmony_ci	int err;
27962306a36Sopenharmony_ci	bool show_progress = false;
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci	if (oe->nr_events == 0)
28262306a36Sopenharmony_ci		return 0;
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci	switch (how) {
28562306a36Sopenharmony_ci	case OE_FLUSH__FINAL:
28662306a36Sopenharmony_ci		show_progress = true;
28762306a36Sopenharmony_ci		fallthrough;
28862306a36Sopenharmony_ci	case OE_FLUSH__TOP:
28962306a36Sopenharmony_ci		oe->next_flush = ULLONG_MAX;
29062306a36Sopenharmony_ci		break;
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	case OE_FLUSH__HALF:
29362306a36Sopenharmony_ci	{
29462306a36Sopenharmony_ci		struct ordered_event *first, *last;
29562306a36Sopenharmony_ci		struct list_head *head = &oe->events;
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci		first = list_entry(head->next, struct ordered_event, list);
29862306a36Sopenharmony_ci		last = oe->last;
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci		/* Warn if we are called before any event got allocated. */
30162306a36Sopenharmony_ci		if (WARN_ONCE(!last || list_empty(head), "empty queue"))
30262306a36Sopenharmony_ci			return 0;
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci		oe->next_flush  = first->timestamp;
30562306a36Sopenharmony_ci		oe->next_flush += (last->timestamp - first->timestamp) / 2;
30662306a36Sopenharmony_ci		break;
30762306a36Sopenharmony_ci	}
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	case OE_FLUSH__TIME:
31062306a36Sopenharmony_ci		oe->next_flush = timestamp;
31162306a36Sopenharmony_ci		show_progress = false;
31262306a36Sopenharmony_ci		break;
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	case OE_FLUSH__ROUND:
31562306a36Sopenharmony_ci	case OE_FLUSH__NONE:
31662306a36Sopenharmony_ci	default:
31762306a36Sopenharmony_ci		break;
31862306a36Sopenharmony_ci	}
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	pr_oe_time(oe->next_flush, "next_flush - ordered_events__flush PRE  %s, nr_events %u\n",
32162306a36Sopenharmony_ci		   str[how], oe->nr_events);
32262306a36Sopenharmony_ci	pr_oe_time(oe->max_timestamp, "max_timestamp\n");
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	err = do_flush(oe, show_progress);
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	if (!err) {
32762306a36Sopenharmony_ci		if (how == OE_FLUSH__ROUND)
32862306a36Sopenharmony_ci			oe->next_flush = oe->max_timestamp;
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci		oe->last_flush_type = how;
33162306a36Sopenharmony_ci	}
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	pr_oe_time(oe->next_flush, "next_flush - ordered_events__flush POST %s, nr_events %u\n",
33462306a36Sopenharmony_ci		   str[how], oe->nr_events);
33562306a36Sopenharmony_ci	pr_oe_time(oe->last_flush, "last_flush\n");
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	return err;
33862306a36Sopenharmony_ci}
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ciint ordered_events__flush(struct ordered_events *oe, enum oe_flush how)
34162306a36Sopenharmony_ci{
34262306a36Sopenharmony_ci	return __ordered_events__flush(oe, how, 0);
34362306a36Sopenharmony_ci}
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ciint ordered_events__flush_time(struct ordered_events *oe, u64 timestamp)
34662306a36Sopenharmony_ci{
34762306a36Sopenharmony_ci	return __ordered_events__flush(oe, OE_FLUSH__TIME, timestamp);
34862306a36Sopenharmony_ci}
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ciu64 ordered_events__first_time(struct ordered_events *oe)
35162306a36Sopenharmony_ci{
35262306a36Sopenharmony_ci	struct ordered_event *event;
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	if (list_empty(&oe->events))
35562306a36Sopenharmony_ci		return 0;
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci	event = list_first_entry(&oe->events, struct ordered_event, list);
35862306a36Sopenharmony_ci	return event->timestamp;
35962306a36Sopenharmony_ci}
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_civoid ordered_events__init(struct ordered_events *oe, ordered_events__deliver_t deliver,
36262306a36Sopenharmony_ci			  void *data)
36362306a36Sopenharmony_ci{
36462306a36Sopenharmony_ci	INIT_LIST_HEAD(&oe->events);
36562306a36Sopenharmony_ci	INIT_LIST_HEAD(&oe->cache);
36662306a36Sopenharmony_ci	INIT_LIST_HEAD(&oe->to_free);
36762306a36Sopenharmony_ci	oe->max_alloc_size = (u64) -1;
36862306a36Sopenharmony_ci	oe->cur_alloc_size = 0;
36962306a36Sopenharmony_ci	oe->deliver	   = deliver;
37062306a36Sopenharmony_ci	oe->data	   = data;
37162306a36Sopenharmony_ci}
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_cistatic void
37462306a36Sopenharmony_ciordered_events_buffer__free(struct ordered_events_buffer *buffer,
37562306a36Sopenharmony_ci			    unsigned int max, struct ordered_events *oe)
37662306a36Sopenharmony_ci{
37762306a36Sopenharmony_ci	if (oe->copy_on_queue) {
37862306a36Sopenharmony_ci		unsigned int i;
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci		for (i = 0; i < max; i++)
38162306a36Sopenharmony_ci			__free_dup_event(oe, buffer->event[i].event);
38262306a36Sopenharmony_ci	}
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	free(buffer);
38562306a36Sopenharmony_ci}
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_civoid ordered_events__free(struct ordered_events *oe)
38862306a36Sopenharmony_ci{
38962306a36Sopenharmony_ci	struct ordered_events_buffer *buffer, *tmp;
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	if (list_empty(&oe->to_free))
39262306a36Sopenharmony_ci		return;
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	/*
39562306a36Sopenharmony_ci	 * Current buffer might not have all the events allocated
39662306a36Sopenharmony_ci	 * yet, we need to free only allocated ones ...
39762306a36Sopenharmony_ci	 */
39862306a36Sopenharmony_ci	if (oe->buffer) {
39962306a36Sopenharmony_ci		list_del_init(&oe->buffer->list);
40062306a36Sopenharmony_ci		ordered_events_buffer__free(oe->buffer, oe->buffer_idx, oe);
40162306a36Sopenharmony_ci	}
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	/* ... and continue with the rest */
40462306a36Sopenharmony_ci	list_for_each_entry_safe(buffer, tmp, &oe->to_free, list) {
40562306a36Sopenharmony_ci		list_del_init(&buffer->list);
40662306a36Sopenharmony_ci		ordered_events_buffer__free(buffer, MAX_SAMPLE_BUFFER, oe);
40762306a36Sopenharmony_ci	}
40862306a36Sopenharmony_ci}
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_civoid ordered_events__reinit(struct ordered_events *oe)
41162306a36Sopenharmony_ci{
41262306a36Sopenharmony_ci	ordered_events__deliver_t old_deliver = oe->deliver;
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	ordered_events__free(oe);
41562306a36Sopenharmony_ci	memset(oe, '\0', sizeof(*oe));
41662306a36Sopenharmony_ci	ordered_events__init(oe, old_deliver, oe->data);
41762306a36Sopenharmony_ci}
418