blob: f5f0fb09403bc57d8f1431142340919a1fb166ea [file]
// 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;
}