1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 2a43783aeSArnaldo Carvalho de Melo #include <errno.h> 3fd20e811SArnaldo Carvalho de Melo #include <inttypes.h> 45f86b80bSJiri Olsa #include <linux/list.h> 5cee3ab9cSJiri Olsa #include <linux/compiler.h> 654bf53b1SAlexander Yarygin #include <linux/string.h> 75f86b80bSJiri Olsa #include "ordered-events.h" 85f86b80bSJiri Olsa #include "session.h" 95f86b80bSJiri Olsa #include "asm/bug.h" 105f86b80bSJiri Olsa #include "debug.h" 118520a98dSArnaldo Carvalho de Melo #include "ui/progress.h" 125f86b80bSJiri Olsa 13cee3ab9cSJiri Olsa #define pr_N(n, fmt, ...) \ 14cee3ab9cSJiri Olsa eprintf(n, debug_ordered_events, fmt, ##__VA_ARGS__) 15cee3ab9cSJiri Olsa 16cee3ab9cSJiri Olsa #define pr(fmt, ...) pr_N(1, pr_fmt(fmt), ##__VA_ARGS__) 17cee3ab9cSJiri Olsa 185f86b80bSJiri Olsa static void queue_event(struct ordered_events *oe, struct ordered_event *new) 195f86b80bSJiri Olsa { 205f86b80bSJiri Olsa struct ordered_event *last = oe->last; 215f86b80bSJiri Olsa u64 timestamp = new->timestamp; 225f86b80bSJiri Olsa struct list_head *p; 235f86b80bSJiri Olsa 245f86b80bSJiri Olsa ++oe->nr_events; 255f86b80bSJiri Olsa oe->last = new; 265f86b80bSJiri Olsa 27cee3ab9cSJiri Olsa pr_oe_time2(timestamp, "queue_event nr_events %u\n", oe->nr_events); 28cee3ab9cSJiri Olsa 295f86b80bSJiri Olsa if (!last) { 305f86b80bSJiri Olsa list_add(&new->list, &oe->events); 315f86b80bSJiri Olsa oe->max_timestamp = timestamp; 325f86b80bSJiri Olsa return; 335f86b80bSJiri Olsa } 345f86b80bSJiri Olsa 355f86b80bSJiri Olsa /* 365f86b80bSJiri Olsa * last event might point to some random place in the list as it's 375f86b80bSJiri Olsa * the last queued event. We expect that the new event is close to 385f86b80bSJiri Olsa * this. 395f86b80bSJiri Olsa */ 405f86b80bSJiri Olsa if (last->timestamp <= timestamp) { 415f86b80bSJiri Olsa while (last->timestamp <= timestamp) { 425f86b80bSJiri Olsa p = last->list.next; 435f86b80bSJiri Olsa if (p == &oe->events) { 445f86b80bSJiri Olsa list_add_tail(&new->list, &oe->events); 455f86b80bSJiri Olsa oe->max_timestamp = timestamp; 465f86b80bSJiri Olsa return; 475f86b80bSJiri Olsa } 485f86b80bSJiri Olsa last = list_entry(p, struct ordered_event, list); 495f86b80bSJiri Olsa } 505f86b80bSJiri Olsa list_add_tail(&new->list, &last->list); 515f86b80bSJiri Olsa } else { 525f86b80bSJiri Olsa while (last->timestamp > timestamp) { 535f86b80bSJiri Olsa p = last->list.prev; 545f86b80bSJiri Olsa if (p == &oe->events) { 555f86b80bSJiri Olsa list_add(&new->list, &oe->events); 565f86b80bSJiri Olsa return; 575f86b80bSJiri Olsa } 585f86b80bSJiri Olsa last = list_entry(p, struct ordered_event, list); 595f86b80bSJiri Olsa } 605f86b80bSJiri Olsa list_add(&new->list, &last->list); 615f86b80bSJiri Olsa } 625f86b80bSJiri Olsa } 635f86b80bSJiri Olsa 6454bf53b1SAlexander Yarygin static union perf_event *__dup_event(struct ordered_events *oe, 6554bf53b1SAlexander Yarygin union perf_event *event) 6654bf53b1SAlexander Yarygin { 6754bf53b1SAlexander Yarygin union perf_event *new_event = NULL; 6854bf53b1SAlexander Yarygin 6954bf53b1SAlexander Yarygin if (oe->cur_alloc_size < oe->max_alloc_size) { 7054bf53b1SAlexander Yarygin new_event = memdup(event, event->header.size); 7154bf53b1SAlexander Yarygin if (new_event) 7254bf53b1SAlexander Yarygin oe->cur_alloc_size += event->header.size; 7354bf53b1SAlexander Yarygin } 7454bf53b1SAlexander Yarygin 7554bf53b1SAlexander Yarygin return new_event; 7654bf53b1SAlexander Yarygin } 7754bf53b1SAlexander Yarygin 7854bf53b1SAlexander Yarygin static union perf_event *dup_event(struct ordered_events *oe, 7954bf53b1SAlexander Yarygin union perf_event *event) 8054bf53b1SAlexander Yarygin { 8154bf53b1SAlexander Yarygin return oe->copy_on_queue ? __dup_event(oe, event) : event; 8254bf53b1SAlexander Yarygin } 8354bf53b1SAlexander Yarygin 84d5ceb62bSJiri Olsa static void __free_dup_event(struct ordered_events *oe, union perf_event *event) 8554bf53b1SAlexander Yarygin { 86d5ceb62bSJiri Olsa if (event) { 8754bf53b1SAlexander Yarygin oe->cur_alloc_size -= event->header.size; 8854bf53b1SAlexander Yarygin free(event); 8954bf53b1SAlexander Yarygin } 9054bf53b1SAlexander Yarygin } 9154bf53b1SAlexander Yarygin 92d5ceb62bSJiri Olsa static void free_dup_event(struct ordered_events *oe, union perf_event *event) 93d5ceb62bSJiri Olsa { 94d5ceb62bSJiri Olsa if (oe->copy_on_queue) 95d5ceb62bSJiri Olsa __free_dup_event(oe, event); 96d5ceb62bSJiri Olsa } 97d5ceb62bSJiri Olsa 985f86b80bSJiri Olsa #define MAX_SAMPLE_BUFFER (64 * 1024 / sizeof(struct ordered_event)) 9954bf53b1SAlexander Yarygin static struct ordered_event *alloc_event(struct ordered_events *oe, 10054bf53b1SAlexander Yarygin union perf_event *event) 1015f86b80bSJiri Olsa { 1025f86b80bSJiri Olsa struct list_head *cache = &oe->cache; 1035f86b80bSJiri Olsa struct ordered_event *new = NULL; 10454bf53b1SAlexander Yarygin union perf_event *new_event; 10553da12e0SJiri Olsa size_t size; 10654bf53b1SAlexander Yarygin 10754bf53b1SAlexander Yarygin new_event = dup_event(oe, event); 10854bf53b1SAlexander Yarygin if (!new_event) 10954bf53b1SAlexander Yarygin return NULL; 1105f86b80bSJiri Olsa 111d5ceb62bSJiri Olsa /* 112d5ceb62bSJiri Olsa * We maintain the following scheme of buffers for ordered 113d5ceb62bSJiri Olsa * event allocation: 114d5ceb62bSJiri Olsa * 115d5ceb62bSJiri Olsa * to_free list -> buffer1 (64K) 116d5ceb62bSJiri Olsa * buffer2 (64K) 117d5ceb62bSJiri Olsa * ... 118d5ceb62bSJiri Olsa * 119d5ceb62bSJiri Olsa * Each buffer keeps an array of ordered events objects: 120d5ceb62bSJiri Olsa * buffer -> event[0] 121d5ceb62bSJiri Olsa * event[1] 122d5ceb62bSJiri Olsa * ... 123d5ceb62bSJiri Olsa * 124d5ceb62bSJiri Olsa * Each allocated ordered event is linked to one of 125d5ceb62bSJiri Olsa * following lists: 126d5ceb62bSJiri Olsa * - time ordered list 'events' 127d5ceb62bSJiri Olsa * - list of currently removed events 'cache' 128d5ceb62bSJiri Olsa * 129d5ceb62bSJiri Olsa * Allocation of the ordered event uses the following order 130d5ceb62bSJiri Olsa * to get the memory: 131d5ceb62bSJiri Olsa * - use recently removed object from 'cache' list 132d5ceb62bSJiri Olsa * - use available object in current allocation buffer 133d5ceb62bSJiri Olsa * - allocate new buffer if the current buffer is full 134d5ceb62bSJiri Olsa * 135d5ceb62bSJiri Olsa * Removal of ordered event object moves it from events to 136d5ceb62bSJiri Olsa * the cache list. 137d5ceb62bSJiri Olsa */ 13853da12e0SJiri Olsa size = sizeof(*oe->buffer) + MAX_SAMPLE_BUFFER * sizeof(*new); 13953da12e0SJiri Olsa 1405f86b80bSJiri Olsa if (!list_empty(cache)) { 1415f86b80bSJiri Olsa new = list_entry(cache->next, struct ordered_event, list); 142e56fbc9dSArnaldo Carvalho de Melo list_del_init(&new->list); 1435f86b80bSJiri Olsa } else if (oe->buffer) { 144d5ceb62bSJiri Olsa new = &oe->buffer->event[oe->buffer_idx]; 1455f86b80bSJiri Olsa if (++oe->buffer_idx == MAX_SAMPLE_BUFFER) 1465f86b80bSJiri Olsa oe->buffer = NULL; 14753da12e0SJiri Olsa } else if ((oe->cur_alloc_size + size) < oe->max_alloc_size) { 1485f86b80bSJiri Olsa oe->buffer = malloc(size); 14954bf53b1SAlexander Yarygin if (!oe->buffer) { 15054bf53b1SAlexander Yarygin free_dup_event(oe, new_event); 1515f86b80bSJiri Olsa return NULL; 15254bf53b1SAlexander Yarygin } 1535f86b80bSJiri Olsa 154cee3ab9cSJiri Olsa pr("alloc size %" PRIu64 "B (+%zu), max %" PRIu64 "B\n", 155cee3ab9cSJiri Olsa oe->cur_alloc_size, size, oe->max_alloc_size); 156cee3ab9cSJiri Olsa 1575f86b80bSJiri Olsa oe->cur_alloc_size += size; 1585f86b80bSJiri Olsa list_add(&oe->buffer->list, &oe->to_free); 1595f86b80bSJiri Olsa 160d5ceb62bSJiri Olsa oe->buffer_idx = 1; 161d5ceb62bSJiri Olsa new = &oe->buffer->event[0]; 162cee3ab9cSJiri Olsa } else { 163cee3ab9cSJiri Olsa pr("allocation limit reached %" PRIu64 "B\n", oe->max_alloc_size); 164d5ceb62bSJiri Olsa return NULL; 1655f86b80bSJiri Olsa } 1665f86b80bSJiri Olsa 16754bf53b1SAlexander Yarygin new->event = new_event; 1685f86b80bSJiri Olsa return new; 1695f86b80bSJiri Olsa } 1705f86b80bSJiri Olsa 1714a6b362fSArnaldo Carvalho de Melo static struct ordered_event * 1724a6b362fSArnaldo Carvalho de Melo ordered_events__new_event(struct ordered_events *oe, u64 timestamp, 17354bf53b1SAlexander Yarygin union perf_event *event) 1745f86b80bSJiri Olsa { 1755f86b80bSJiri Olsa struct ordered_event *new; 1765f86b80bSJiri Olsa 17754bf53b1SAlexander Yarygin new = alloc_event(oe, event); 1785f86b80bSJiri Olsa if (new) { 1795f86b80bSJiri Olsa new->timestamp = timestamp; 1805f86b80bSJiri Olsa queue_event(oe, new); 1815f86b80bSJiri Olsa } 1825f86b80bSJiri Olsa 1835f86b80bSJiri Olsa return new; 1845f86b80bSJiri Olsa } 1855f86b80bSJiri Olsa 1865f86b80bSJiri Olsa void ordered_events__delete(struct ordered_events *oe, struct ordered_event *event) 1875f86b80bSJiri Olsa { 188fa4e5c67SJiri Olsa list_move(&event->list, &oe->cache); 1895f86b80bSJiri Olsa oe->nr_events--; 19054bf53b1SAlexander Yarygin free_dup_event(oe, event->event); 1911e0d4f02SDavid Carrillo-Cisneros event->event = NULL; 1925f86b80bSJiri Olsa } 1935f86b80bSJiri Olsa 1944a6b362fSArnaldo Carvalho de Melo int ordered_events__queue(struct ordered_events *oe, union perf_event *event, 195*2292083fSAlexey Bayduraev u64 timestamp, u64 file_offset, const char *file_path) 1964a6b362fSArnaldo Carvalho de Melo { 1974a6b362fSArnaldo Carvalho de Melo struct ordered_event *oevent; 1984a6b362fSArnaldo Carvalho de Melo 1994a6b362fSArnaldo Carvalho de Melo if (!timestamp || timestamp == ~0ULL) 2004a6b362fSArnaldo Carvalho de Melo return -ETIME; 2014a6b362fSArnaldo Carvalho de Melo 2024a6b362fSArnaldo Carvalho de Melo if (timestamp < oe->last_flush) { 2034a6b362fSArnaldo Carvalho de Melo pr_oe_time(timestamp, "out of order event\n"); 2044a6b362fSArnaldo Carvalho de Melo pr_oe_time(oe->last_flush, "last flush, last_flush_type %d\n", 2054a6b362fSArnaldo Carvalho de Melo oe->last_flush_type); 2064a6b362fSArnaldo Carvalho de Melo 2079870d780SArnaldo Carvalho de Melo oe->nr_unordered_events++; 2084a6b362fSArnaldo Carvalho de Melo } 2094a6b362fSArnaldo Carvalho de Melo 2104a6b362fSArnaldo Carvalho de Melo oevent = ordered_events__new_event(oe, timestamp, event); 2114a6b362fSArnaldo Carvalho de Melo if (!oevent) { 2124a6b362fSArnaldo Carvalho de Melo ordered_events__flush(oe, OE_FLUSH__HALF); 2134a6b362fSArnaldo Carvalho de Melo oevent = ordered_events__new_event(oe, timestamp, event); 2144a6b362fSArnaldo Carvalho de Melo } 2154a6b362fSArnaldo Carvalho de Melo 2164a6b362fSArnaldo Carvalho de Melo if (!oevent) 2174a6b362fSArnaldo Carvalho de Melo return -ENOMEM; 2184a6b362fSArnaldo Carvalho de Melo 2194a6b362fSArnaldo Carvalho de Melo oevent->file_offset = file_offset; 220*2292083fSAlexey Bayduraev oevent->file_path = file_path; 2214a6b362fSArnaldo Carvalho de Melo return 0; 2224a6b362fSArnaldo Carvalho de Melo } 2234a6b362fSArnaldo Carvalho de Melo 22468ca5d07SJiri Olsa static int do_flush(struct ordered_events *oe, bool show_progress) 2255f86b80bSJiri Olsa { 2265f86b80bSJiri Olsa struct list_head *head = &oe->events; 2275f86b80bSJiri Olsa struct ordered_event *tmp, *iter; 2285f86b80bSJiri Olsa u64 limit = oe->next_flush; 2295f86b80bSJiri Olsa u64 last_ts = oe->last ? oe->last->timestamp : 0ULL; 2305f86b80bSJiri Olsa struct ui_progress prog; 2315f86b80bSJiri Olsa int ret; 2325f86b80bSJiri Olsa 23328083681SArnaldo Carvalho de Melo if (!limit) 2345f86b80bSJiri Olsa return 0; 2355f86b80bSJiri Olsa 2365f86b80bSJiri Olsa if (show_progress) 2375f86b80bSJiri Olsa ui_progress__init(&prog, oe->nr_events, "Processing time ordered events..."); 2385f86b80bSJiri Olsa 2395f86b80bSJiri Olsa list_for_each_entry_safe(iter, tmp, head, list) { 2405f86b80bSJiri Olsa if (session_done()) 2415f86b80bSJiri Olsa return 0; 2425f86b80bSJiri Olsa 2435f86b80bSJiri Olsa if (iter->timestamp > limit) 2445f86b80bSJiri Olsa break; 2459870d780SArnaldo Carvalho de Melo ret = oe->deliver(oe, iter); 2465f86b80bSJiri Olsa if (ret) 2475f86b80bSJiri Olsa return ret; 2485f86b80bSJiri Olsa 2495f86b80bSJiri Olsa ordered_events__delete(oe, iter); 2505f86b80bSJiri Olsa oe->last_flush = iter->timestamp; 2515f86b80bSJiri Olsa 2525f86b80bSJiri Olsa if (show_progress) 2535f86b80bSJiri Olsa ui_progress__update(&prog, 1); 2545f86b80bSJiri Olsa } 2555f86b80bSJiri Olsa 2565f86b80bSJiri Olsa if (list_empty(head)) 2575f86b80bSJiri Olsa oe->last = NULL; 2585f86b80bSJiri Olsa else if (last_ts <= limit) 2595f86b80bSJiri Olsa oe->last = list_entry(head->prev, struct ordered_event, list); 2605f86b80bSJiri Olsa 2615c9ce1e6SArnaldo Carvalho de Melo if (show_progress) 2625c9ce1e6SArnaldo Carvalho de Melo ui_progress__finish(); 2635c9ce1e6SArnaldo Carvalho de Melo 2645f86b80bSJiri Olsa return 0; 2655f86b80bSJiri Olsa } 2665f86b80bSJiri Olsa 26768ca5d07SJiri Olsa static int __ordered_events__flush(struct ordered_events *oe, enum oe_flush how, 26868ca5d07SJiri Olsa u64 timestamp) 2695f86b80bSJiri Olsa { 270cee3ab9cSJiri Olsa static const char * const str[] = { 271b0a45203SJiri Olsa "NONE", 272cee3ab9cSJiri Olsa "FINAL", 273cee3ab9cSJiri Olsa "ROUND", 274cee3ab9cSJiri Olsa "HALF ", 2751e5b0cf8SChangbin Du "TOP ", 2761e5b0cf8SChangbin Du "TIME ", 277cee3ab9cSJiri Olsa }; 2785f86b80bSJiri Olsa int err; 279b8494f1dSJiri Olsa bool show_progress = false; 2805f86b80bSJiri Olsa 28128083681SArnaldo Carvalho de Melo if (oe->nr_events == 0) 28228083681SArnaldo Carvalho de Melo return 0; 28328083681SArnaldo Carvalho de Melo 2845f86b80bSJiri Olsa switch (how) { 2855f86b80bSJiri Olsa case OE_FLUSH__FINAL: 286b8494f1dSJiri Olsa show_progress = true; 28716c66bc1SJiri Olsa __fallthrough; 28816c66bc1SJiri Olsa case OE_FLUSH__TOP: 28916c66bc1SJiri Olsa oe->next_flush = ULLONG_MAX; 2905f86b80bSJiri Olsa break; 2915f86b80bSJiri Olsa 2925f86b80bSJiri Olsa case OE_FLUSH__HALF: 2935f86b80bSJiri Olsa { 2945f86b80bSJiri Olsa struct ordered_event *first, *last; 2955f86b80bSJiri Olsa struct list_head *head = &oe->events; 2965f86b80bSJiri Olsa 2975f86b80bSJiri Olsa first = list_entry(head->next, struct ordered_event, list); 2985f86b80bSJiri Olsa last = oe->last; 2995f86b80bSJiri Olsa 3005f86b80bSJiri Olsa /* Warn if we are called before any event got allocated. */ 3015f86b80bSJiri Olsa if (WARN_ONCE(!last || list_empty(head), "empty queue")) 3025f86b80bSJiri Olsa return 0; 3035f86b80bSJiri Olsa 3045f86b80bSJiri Olsa oe->next_flush = first->timestamp; 3055f86b80bSJiri Olsa oe->next_flush += (last->timestamp - first->timestamp) / 2; 3065f86b80bSJiri Olsa break; 3075f86b80bSJiri Olsa } 3085f86b80bSJiri Olsa 30968ca5d07SJiri Olsa case OE_FLUSH__TIME: 31068ca5d07SJiri Olsa oe->next_flush = timestamp; 31168ca5d07SJiri Olsa show_progress = false; 31268ca5d07SJiri Olsa break; 31368ca5d07SJiri Olsa 3145f86b80bSJiri Olsa case OE_FLUSH__ROUND: 315b0a45203SJiri Olsa case OE_FLUSH__NONE: 3165f86b80bSJiri Olsa default: 3175f86b80bSJiri Olsa break; 3188284bbeaSZou Wei } 3195f86b80bSJiri Olsa 320cee3ab9cSJiri Olsa pr_oe_time(oe->next_flush, "next_flush - ordered_events__flush PRE %s, nr_events %u\n", 321cee3ab9cSJiri Olsa str[how], oe->nr_events); 322cee3ab9cSJiri Olsa pr_oe_time(oe->max_timestamp, "max_timestamp\n"); 323cee3ab9cSJiri Olsa 32468ca5d07SJiri Olsa err = do_flush(oe, show_progress); 3255f86b80bSJiri Olsa 3265f86b80bSJiri Olsa if (!err) { 3275f86b80bSJiri Olsa if (how == OE_FLUSH__ROUND) 3285f86b80bSJiri Olsa oe->next_flush = oe->max_timestamp; 329b0a45203SJiri Olsa 330b0a45203SJiri Olsa oe->last_flush_type = how; 3315f86b80bSJiri Olsa } 3325f86b80bSJiri Olsa 333cee3ab9cSJiri Olsa pr_oe_time(oe->next_flush, "next_flush - ordered_events__flush POST %s, nr_events %u\n", 334cee3ab9cSJiri Olsa str[how], oe->nr_events); 335cee3ab9cSJiri Olsa pr_oe_time(oe->last_flush, "last_flush\n"); 336cee3ab9cSJiri Olsa 3375f86b80bSJiri Olsa return err; 3385f86b80bSJiri Olsa } 33936522f5cSJiri Olsa 34068ca5d07SJiri Olsa int ordered_events__flush(struct ordered_events *oe, enum oe_flush how) 34168ca5d07SJiri Olsa { 34268ca5d07SJiri Olsa return __ordered_events__flush(oe, how, 0); 34368ca5d07SJiri Olsa } 34468ca5d07SJiri Olsa 34568ca5d07SJiri Olsa int ordered_events__flush_time(struct ordered_events *oe, u64 timestamp) 34668ca5d07SJiri Olsa { 34768ca5d07SJiri Olsa return __ordered_events__flush(oe, OE_FLUSH__TIME, timestamp); 34868ca5d07SJiri Olsa } 34968ca5d07SJiri Olsa 35083356b3dSJiri Olsa u64 ordered_events__first_time(struct ordered_events *oe) 35183356b3dSJiri Olsa { 35283356b3dSJiri Olsa struct ordered_event *event; 35383356b3dSJiri Olsa 35483356b3dSJiri Olsa if (list_empty(&oe->events)) 35583356b3dSJiri Olsa return 0; 35683356b3dSJiri Olsa 35783356b3dSJiri Olsa event = list_first_entry(&oe->events, struct ordered_event, list); 35883356b3dSJiri Olsa return event->timestamp; 35983356b3dSJiri Olsa } 36083356b3dSJiri Olsa 361a4a6668aSJiri Olsa void ordered_events__init(struct ordered_events *oe, ordered_events__deliver_t deliver, 362a4a6668aSJiri Olsa void *data) 36336522f5cSJiri Olsa { 36436522f5cSJiri Olsa INIT_LIST_HEAD(&oe->events); 36536522f5cSJiri Olsa INIT_LIST_HEAD(&oe->cache); 36636522f5cSJiri Olsa INIT_LIST_HEAD(&oe->to_free); 36736522f5cSJiri Olsa oe->max_alloc_size = (u64) -1; 36836522f5cSJiri Olsa oe->cur_alloc_size = 0; 369d10eb1ebSArnaldo Carvalho de Melo oe->deliver = deliver; 370a4a6668aSJiri Olsa oe->data = data; 37136522f5cSJiri Olsa } 372adc56ed1SJiri Olsa 373d5ceb62bSJiri Olsa static void 374d5ceb62bSJiri Olsa ordered_events_buffer__free(struct ordered_events_buffer *buffer, 375d5ceb62bSJiri Olsa unsigned int max, struct ordered_events *oe) 376d5ceb62bSJiri Olsa { 377d5ceb62bSJiri Olsa if (oe->copy_on_queue) { 378d5ceb62bSJiri Olsa unsigned int i; 379d5ceb62bSJiri Olsa 380d5ceb62bSJiri Olsa for (i = 0; i < max; i++) 381d5ceb62bSJiri Olsa __free_dup_event(oe, buffer->event[i].event); 382d5ceb62bSJiri Olsa } 383d5ceb62bSJiri Olsa 384d5ceb62bSJiri Olsa free(buffer); 385d5ceb62bSJiri Olsa } 386d5ceb62bSJiri Olsa 387adc56ed1SJiri Olsa void ordered_events__free(struct ordered_events *oe) 388adc56ed1SJiri Olsa { 389d5ceb62bSJiri Olsa struct ordered_events_buffer *buffer, *tmp; 390adc56ed1SJiri Olsa 391d5ceb62bSJiri Olsa if (list_empty(&oe->to_free)) 392d5ceb62bSJiri Olsa return; 393d5ceb62bSJiri Olsa 394d5ceb62bSJiri Olsa /* 395d5ceb62bSJiri Olsa * Current buffer might not have all the events allocated 396d5ceb62bSJiri Olsa * yet, we need to free only allocated ones ... 397d5ceb62bSJiri Olsa */ 39899d86c8bSJiri Olsa if (oe->buffer) { 399e56fbc9dSArnaldo Carvalho de Melo list_del_init(&oe->buffer->list); 400d5ceb62bSJiri Olsa ordered_events_buffer__free(oe->buffer, oe->buffer_idx, oe); 40199d86c8bSJiri Olsa } 402d5ceb62bSJiri Olsa 403d5ceb62bSJiri Olsa /* ... and continue with the rest */ 404d5ceb62bSJiri Olsa list_for_each_entry_safe(buffer, tmp, &oe->to_free, list) { 405e56fbc9dSArnaldo Carvalho de Melo list_del_init(&buffer->list); 406d5ceb62bSJiri Olsa ordered_events_buffer__free(buffer, MAX_SAMPLE_BUFFER, oe); 407adc56ed1SJiri Olsa } 408adc56ed1SJiri Olsa } 4094532f642SWang Nan 4104532f642SWang Nan void ordered_events__reinit(struct ordered_events *oe) 4114532f642SWang Nan { 4124532f642SWang Nan ordered_events__deliver_t old_deliver = oe->deliver; 4134532f642SWang Nan 4144532f642SWang Nan ordered_events__free(oe); 4154532f642SWang Nan memset(oe, '\0', sizeof(*oe)); 416a4a6668aSJiri Olsa ordered_events__init(oe, old_deliver, oe->data); 4174532f642SWang Nan } 418