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