diff options
Diffstat (limited to 'lib/trace-cmd/trace-filter-hash.c')
-rw-r--r-- | lib/trace-cmd/trace-filter-hash.c | 211 |
1 files changed, 211 insertions, 0 deletions
diff --git a/lib/trace-cmd/trace-filter-hash.c b/lib/trace-cmd/trace-filter-hash.c new file mode 100644 index 00000000..f5f0fb09 --- /dev/null +++ b/lib/trace-cmd/trace-filter-hash.c @@ -0,0 +1,211 @@ +// SPDX-License-Identifier: LGPL-2.1 +/* + * Copyright (C) 2009, Steven Rostedt <srostedt@redhat.com> + * Copyright (C) 2018 VMware Inc, Steven Rostedt <rostedt@goodmis.org> + * + */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#include <assert.h> + +#include "trace-filter-hash.h" + +#define FILTER_HASH_BITS 8 +#define FILTER_HASH_SIZE (1 << FILTER_HASH_BITS) + +struct tracecmd_filter_id_item * +tracecmd_filter_id_find(struct tracecmd_filter_id *hash, int id) +{ + int key = tracecmd_quick_hash(id, FILTER_HASH_BITS); + struct tracecmd_filter_id_item *item = hash->hash[key]; + + while (item) { + if (item->id == id) + break; + item = item->next; + } + + return item; +} + +void tracecmd_filter_id_add(struct tracecmd_filter_id *hash, int id) +{ + int key = tracecmd_quick_hash(id, FILTER_HASH_BITS); + struct tracecmd_filter_id_item *item; + + item = calloc(1, sizeof(*item)); + assert(item); + + item->id = id; + item->next = hash->hash[key]; + hash->hash[key] = item; + + hash->count++; +} + +void tracecmd_filter_id_remove(struct tracecmd_filter_id *hash, int id) +{ + int key = tracecmd_quick_hash(id, FILTER_HASH_BITS); + struct tracecmd_filter_id_item **next = &hash->hash[key]; + struct tracecmd_filter_id_item *item; + + while (*next) { + if ((*next)->id == id) + break; + next = &(*next)->next; + } + + if (!*next) + return; + + assert(hash->count); + hash->count--; + + item = *next; + + *next = item->next; + + free(item); +} + +void tracecmd_filter_id_clear(struct tracecmd_filter_id *hash) +{ + struct tracecmd_filter_id_item *item, *next; + int i; + + for (i = 0; i < FILTER_HASH_SIZE; i++) { + next = hash->hash[i]; + if (!next) + continue; + + hash->hash[i] = NULL; + while (next) { + item = next; + next = item->next; + free(item); + } + } + + hash->count = 0; +} + +struct tracecmd_filter_id *tracecmd_filter_id_hash_alloc(void) +{ + struct tracecmd_filter_id *hash; + + hash = calloc(1, sizeof(*hash)); + assert(hash); + hash->hash = calloc(FILTER_HASH_SIZE, sizeof(*hash->hash)); + hash->count = 0; + + return hash; +} + +void tracecmd_filter_id_hash_free(struct tracecmd_filter_id *hash) +{ + if (!hash) + return; + + tracecmd_filter_id_clear(hash); + free(hash->hash); + free(hash); +} + +struct tracecmd_filter_id * +tracecmd_filter_id_hash_copy(struct tracecmd_filter_id *hash) +{ + struct tracecmd_filter_id *new_hash; + struct tracecmd_filter_id_item *item, **pitem; + int i; + + if (!hash) + return NULL; + + new_hash = tracecmd_filter_id_hash_alloc(); + assert(new_hash); + + for (i = 0; i < FILTER_HASH_SIZE; i++) { + item = hash->hash[i]; + if (!item) + continue; + + pitem = &new_hash->hash[i]; + + while (item) { + *pitem = calloc(1, sizeof(*item)); + assert(*pitem); + **pitem = *item; + + pitem = &(*pitem)->next; + item = item->next; + } + } + + new_hash->count = hash->count; + return new_hash; +} + +int *tracecmd_filter_ids(struct tracecmd_filter_id *hash) +{ + struct tracecmd_filter_id_item *item; + int *ids; + int count = 0; + int i; + + if (!hash->count) + return NULL; + + ids = malloc(sizeof(*ids) * (hash->count + 1)); + if (!ids) + return NULL; + + for (i = 0; i < FILTER_HASH_SIZE; i++) { + item = hash->hash[i]; + while (item) { + ids[count++] = item->id; + item = item->next; + } + } + + ids[count] = -1; + return ids; +} + +/** + * filter_id_compare - compare two id hashes to see if they are equal + * @hash1: one hash to compare + * @hash2: another hash to compare to @hash1 + * + * Returns 1 if the two hashes are the same, 0 otherwise. + */ +int tracecmd_filter_id_compare(struct tracecmd_filter_id *hash1, + struct tracecmd_filter_id *hash2) +{ + int *ids; + int ret = 0; + int i; + + /* If counts don't match, then they obviously are not the same */ + if (hash1->count != hash2->count) + return 0; + + /* If both hashes are empty, they are the same */ + if (!hash1->count && !hash2->count) + return 1; + + /* Now compare the pids of one hash with the other */ + ids = tracecmd_filter_ids(hash1); + for (i = 0; ids[i] >= 0; i++) { + if (!tracecmd_filter_id_find(hash2, ids[i])) + break; + } + + if (ids[i] == -1) + ret = 1; + + free(ids); + + return ret; +} |