Comprehensive C Archive Network

Upload Code Download Code About

Browse Source Download (without any required ccan dependencies)

Module:

talloc_link

Summary:

link helper for talloc

Author:

Rusty Russell <rusty@rustcorp.com.au>

Dependencies:

 ccan/talloc ccan/list  

Description:

Talloc references can be confusing and buggy. In the cases where an object needs multiple parents, all parents need to be aware of the situation; thus talloc_link is a helper where all "parents" talloc_link an object they agree to share ownership of.

Example:

// Silly program which keeps a cache of uppercased strings.
// The cache wants to keep strings around even after they may have
// been "freed" by the caller.
#include <stdio.h>
#include <err.h>
#include <string.h>
#include <ctype.h>
#include <ccan/talloc/talloc.h>
#include <ccan/talloc_link/talloc_link.h>

struct upcache {
        const char *str;
        const char *upstr;
};

static struct upcache *cache;
static unsigned int cache_hits = 0;
#define CACHE_SIZE 4
static void init_upcase(void)
{
        cache = talloc_zero_array(NULL, struct upcache, CACHE_SIZE);
}

static struct upcache *lookup_upcase(const char *str)
{
        unsigned int i;
        for (i = 0; i < CACHE_SIZE; i++)
                if (cache[i].str && !strcmp(cache[i].str, str)) {
                        cache_hits++;
                        return &cache[i];
                }
        return NULL;
}

static struct upcache *new_upcase(const char *str)
{
        unsigned int i;
        char *upstr;

        upstr = talloc_linked(cache, talloc_strdup(NULL, str));
        if (!upstr)
                return NULL;

        i = random() % CACHE_SIZE;

        // Throw out old: works fine if cache[i].upstr is NULL.
        talloc_delink(cache, cache[i].upstr);

        // Replace with new.
        cache[i].str = str;
        cache[i].upstr = upstr;
        while (*upstr) {
                *upstr = toupper(*upstr);
                upstr++;
        }
        return &cache[i];
}

// If you want to keep the result, talloc_link it.
static const char *get_upcase(const char *str)
{
        struct upcache *uc = lookup_upcase(str);
        if (!uc)
                uc = new_upcase(str);
        if (!uc)
                return NULL;
        return uc->upstr;
}

static void exit_upcase(void)
{
        talloc_free(cache);
        printf("Cache hits: %u\n", cache_hits);
}

int main(int argc, char *argv[])
{
        unsigned int i;
        const char **values;

        // Will dump any memory leaks to stderr on exit.
        talloc_enable_leak_report();

        // Initialize cache.
        init_upcase();

        // Throw values in.
        values = talloc_array(NULL, const char *, argc);
        for (i = 1; i < argc; i++) {
                values[i-1] = talloc_link(values, get_upcase(argv[i]));
                if (!values[i-1])
                        err(1, "Out of memory");
        }
        // This will free all the values, but cache will still work.
        talloc_free(values);

        // Repeat!
        values = talloc_array(NULL, const char *, argc);
        for (i = 1; i < argc; i++) {
                values[i-1] = talloc_link(values, get_upcase(argv[i]));
                if (!values[i-1])
                        err(1, "Out of memory");
        }

        // This will remove cache links, but we still have a link.
        exit_upcase();

        // Show values, so we output something.
        for (i = 0; i < argc - 1; i++)
                printf("%s ", values[i]);
        printf("\n");

        // This will finally free the upcase strings (last link).
        talloc_free(values);

        return 0;
}

License:

GPL (v2 or any later version)