libosmocore 1.9.0.192-1c24
Osmocom core library
Use Counter

Generic object usage counter (get, put and deallocate on zero count). More...

Files

file  use_count.h
 Generic object usage counter API (get, put and deallocate on zero count).
 
file  use_count.c
 Generic object usage counter Implementation (get, put and deallocate on zero count).
 

Data Structures

struct  osmo_use_count
 Use counter state for one used object, managing N distinct named counters. More...
 
struct  osmo_use_count_entry
 One named counter in the list managed by osmo_use_count. More...
 

Macros

#define osmo_use_count_get_put(USE_LIST, USE, CHANGE)    _osmo_use_count_get_put(USE_LIST, USE, CHANGE, __FILE__, __LINE__)
 Change the use count for a given use token. More...
 

Typedefs

typedef int(* osmo_use_count_cb_t) (struct osmo_use_count_entry *use_count_entry, int32_t old_use_count, const char *file, int line)
 Invoked when a use count changes. More...
 

Functions

int _osmo_use_count_get_put (struct osmo_use_count *uc, const char *use, int32_t change, const char *file, int line)
 Implementation for osmo_use_count_get_put(), which can also be directly invoked to pass source file information. More...
 
const char * osmo_use_count_name_buf (char *buf, size_t buf_len, const struct osmo_use_count *uc)
 Write a comprehensive listing of use counts to a string buffer. More...
 
int osmo_use_count_to_str_buf (char *buf, size_t buf_len, const struct osmo_use_count *uc)
 Write a comprehensive listing of use counts to a string buffer. More...
 
char * osmo_use_count_to_str_c (void *ctx, const struct osmo_use_count *uc)
 Write a comprehensive listing of use counts to a talloc allocated string buffer. More...
 
int32_t osmo_use_count_total (const struct osmo_use_count *uc)
 Return the sum of all use counts, min- and max-clamped at INT32_MIN and INT32_MAX. More...
 
int32_t osmo_use_count_by (const struct osmo_use_count *uc, const char *use)
 Return use count by a single use token. More...
 
struct osmo_use_count_entryosmo_use_count_find (const struct osmo_use_count *uc, const char *use)
 
void osmo_use_count_free (struct osmo_use_count_entry *use_count_entry)
 Deallocate a use count entry. More...
 
void osmo_use_count_make_static_entries (struct osmo_use_count *uc, struct osmo_use_count_entry *buf, size_t buf_n_entries)
 Add N static use token entries to avoid dynamic allocation of use count tokens. More...
 
static bool count_safe (int32_t *val_p, int32_t add)
 Add two int32_t but make sure to min- and max-clamp at INT32_MIN and INT32_MAX, respectively. More...
 
static struct osmo_use_count_entryosmo_use_count_repurpose_zero_entry (struct osmo_use_count *uc, const char *use)
 Find a use count entry that currently has zero count, and re-use that for this new use token. More...
 
static struct osmo_use_count_entryosmo_use_count_create (struct osmo_use_count *uc, const char *use)
 Allocate a new use count entry, happens implicitly in osmo_use_count_get_put(). More...
 

Detailed Description

Generic object usage counter (get, put and deallocate on zero count).

For an example and a detailed description, see struct osmo_use_count.

Macro Definition Documentation

◆ osmo_use_count_get_put

#define osmo_use_count_get_put (   USE_LIST,
  USE,
  CHANGE 
)     _osmo_use_count_get_put(USE_LIST, USE, CHANGE, __FILE__, __LINE__)

Change the use count for a given use token.

Parameters
USE_LISTA struct osmo_use_count*, e.g. &my_obj->use_count.
USEA use token: arbitrary string (const char*). This must remain valid memory, e.g. string constants.
CHANGESigned integer value to add to the use count: positive means get(), negative means put().
Returns
Negative on range violations or USE_LIST == NULL, the use_cb()'s return value, or 0 on success.

Typedef Documentation

◆ osmo_use_count_cb_t

typedef int(* osmo_use_count_cb_t) (struct osmo_use_count_entry *use_count_entry, int32_t old_use_count, const char *file, int line)

Invoked when a use count changes.

The implementation is free to trigger actions on arbitrary use count changes, typically to free the use_count->talloc_object when the total use count reaches zero.

The implementation may modify use_count_entry->count, for example for handling of get()/put() bugs, to clamp specific use tokens to specific counts, or to prevent the caller from put()ting into negative counts. When returning an error, there is no implicit undo – if errors need to be corrected, this function is responsible for that.

Be aware: use token strings are not copied, and use count entries usually remain listed also when they reach a zero count. This is trivially perfectly ok when using string literals as use tokens. It is also possible to use dynamically allocated string tokens, but should a use token string become invalid memory when reaching zero count, it is the responsibility of this function to set the use_count_entry->use = NULL; this is required to avoid subsequent osmo_use_count_get_put() invocations from calling strcmp() on invalid memory. (Setting use = NULL cannot be done implicitly after this callback invocation, because callback implementations are allowed to completely deallocate the talloc_object and the use_count list entries, and setting use = NULL after that would be a use-after-free.)

Parameters
[in]use_count_entryUse count entry that is being modified.
[in]old_use_countUse count the item had before the change in use count.
[in]fileSource file string, passed in as FILE from macro osmo_use_count_get_put().
[in]lineSource file line, passed in as LINE from macro osmo_use_count_get_put().
Returns
0 on success, negative if any undesired use count is reached; this rc will be returned by osmo_use_count_get_put().

Function Documentation

◆ _osmo_use_count_get_put()

int _osmo_use_count_get_put ( struct osmo_use_count uc,
const char *  use,
int32_t  change,
const char *  file,
int  line 
)

Implementation for osmo_use_count_get_put(), which can also be directly invoked to pass source file information.

For arguments besides file and line, see osmo_use_count_get_put().

Parameters
[in]fileSource file path, as in FILE.
[in]lineSource file line, as in LINE.

References osmo_use_count_entry::count, count_safe(), osmo_use_count_entry::entry, file(), llist_add_tail(), llist_del(), osmo_use_count_create(), osmo_use_count_find(), osmo_use_count_repurpose_zero_entry(), osmo_use_count_entry::use, osmo_use_count::use_cb, and osmo_use_count::use_counts.

◆ count_safe()

static bool count_safe ( int32_t *  val_p,
int32_t  add 
)
inlinestatic

Add two int32_t but make sure to min- and max-clamp at INT32_MIN and INT32_MAX, respectively.

Referenced by _osmo_use_count_get_put(), and osmo_use_count_total().

◆ osmo_use_count_by()

int32_t osmo_use_count_by ( const struct osmo_use_count uc,
const char *  use 
)

Return use count by a single use token.

Parameters
[in]ucUse counts to look up in.
[in]useUse token.
Returns
Use count, or 0 if uc is NULL or use token is not present.

References osmo_use_count_entry::count, osmo_use_count_find(), and osmo_use_count_entry::use.

◆ osmo_use_count_create()

static struct osmo_use_count_entry * osmo_use_count_create ( struct osmo_use_count uc,
const char *  use 
)
static

◆ osmo_use_count_find()

◆ osmo_use_count_free()

void osmo_use_count_free ( struct osmo_use_count_entry use_count_entry)

Deallocate a use count entry.

Normally, this is not necessary – it is ok and even desirable to leave use count entries around even when they reach a count of zero, until the use_count->talloc_object deallocates and removes all of them in one flush. This avoids repeated allocation and deallocation for use tokens, because use count entries that have reached zero count are repurposed for any other use tokens. A cleanup makes sense only if a very large number of differing use tokens surged at the same time, and the owning object will not be deallocated soon; if so, this should be done by the osmo_use_count_cb_t implementation.

osmo_use_count_free() must not be called on use count entries that were added by osmo_use_count_make_static_entries(). This is the responsibility of the osmo_use_count_cb_t() implementation.

Parameters
[in]use_count_entryUse count entry to unlist and free.

References osmo_use_count_entry::entry, and llist_del().

◆ osmo_use_count_make_static_entries()

void osmo_use_count_make_static_entries ( struct osmo_use_count uc,
struct osmo_use_count_entry buf,
size_t  buf_n_entries 
)

Add N static use token entries to avoid dynamic allocation of use count tokens.

When not using this function, use count entries are talloc allocated from uc->talloc_object as talloc context. This means that there are small dynamic allocations for each use count token. osmo_use_count_get_put() normally leaves zero-count entries around and re-purposes them later, so the number of small allocations is at most the number of concurrent differently-named uses of the same object. If that is not enough, this function allows completely avoiding dynamic use count allocations, by adding N static entries with a zero count and a NULL use token. They will be used by osmo_use_count_get_put(), and, if the caller avoids using osmo_use_count_free(), the osmo_use_count implementation never deallocates them. The idea is that the entries are members of the uc->talloc_object, or that they will by other means be implicitly deallocated by the talloc_object. It is fine to call osmo_use_count_make_static_entries(buf_n_entries=N) and later have more than N concurrent uses, i.e. it is no problem to mix static and dynamic entries. To completely avoid dynamic use count entries, N has to >= the maximum number of concurrent differently-named uses that will occur in the lifetime of the talloc_object.

struct my_object { struct osmo_use_count use_count; struct osmo_use_count_entry use_count_buf[3]; // planning for 3 concurrent users };

void example() { struct my_object *o = talloc_zero(ctx, struct my_object); osmo_use_count_make_static_entries(&o->use_count, o->use_count_buf, ARRAY_SIZE(o->use_count_buf)); }

References osmo_use_count_entry::entry, INIT_LLIST_HEAD, llist_add_tail(), llist_head::next, osmo_use_count_entry::use_count, and osmo_use_count::use_counts.

◆ osmo_use_count_name_buf()

const char * osmo_use_count_name_buf ( char *  buf,
size_t  buf_len,
const struct osmo_use_count uc 
)

Write a comprehensive listing of use counts to a string buffer.

Reads like "12 (3*barring,fighting,8*kungfoo)".

Parameters
[in,out]bufDestination buffer.
[in]buf_lensizeof(buf).
[in]ucUse counts to print.
Returns
buf, always nul-terminated (except when buf_len < 1).

References osmo_use_count_to_str_buf().

◆ osmo_use_count_repurpose_zero_entry()

static struct osmo_use_count_entry * osmo_use_count_repurpose_zero_entry ( struct osmo_use_count uc,
const char *  use 
)
static

Find a use count entry that currently has zero count, and re-use that for this new use token.

References osmo_use_count_entry::count, osmo_use_count_entry::entry, llist_for_each_entry, llist_head::next, osmo_use_count_entry::use, and osmo_use_count::use_counts.

Referenced by _osmo_use_count_get_put().

◆ osmo_use_count_to_str_buf()

int osmo_use_count_to_str_buf ( char *  buf,
size_t  buf_len,
const struct osmo_use_count uc 
)

Write a comprehensive listing of use counts to a string buffer.

Reads like "12 (3*barring,fighting,8*kungfoo)".

Parameters
[in,out]bufDestination buffer.
[in]buf_lensizeof(buf).
[in]ucUse counts to print.
Returns
number of bytes that would be written, like snprintf().

References osmo_strbuf::buf, osmo_strbuf::chars_needed, osmo_use_count_entry::count, osmo_use_count_entry::entry, llist_for_each_entry, llist_head::next, OSMO_STRBUF_PRINTF, osmo_use_count_total(), osmo_use_count_entry::use, and osmo_use_count::use_counts.

Referenced by osmo_use_count_name_buf(), and osmo_use_count_to_str_c().

◆ osmo_use_count_to_str_c()

char * osmo_use_count_to_str_c ( void *  ctx,
const struct osmo_use_count uc 
)

Write a comprehensive listing of use counts to a talloc allocated string buffer.

Reads like "12 (3*barring,fighting,8*kungfoo)".

Parameters
[in]ctxtalloc pool to allocate from.
[in]ucUse counts to print.
Returns
buf, always nul-terminated.

References OSMO_NAME_C_IMPL, and osmo_use_count_to_str_buf().

◆ osmo_use_count_total()

int32_t osmo_use_count_total ( const struct osmo_use_count uc)

Return the sum of all use counts, min- and max-clamped at INT32_MIN and INT32_MAX.

Parameters
[in]ucUse counts to sum up.
Returns
Accumulated counts, or 0 if uc is NULL.

References osmo_use_count_entry::count, count_safe(), osmo_use_count_entry::entry, llist_for_each_entry, llist_head::next, and osmo_use_count::use_counts.

Referenced by osmo_use_count_to_str_buf().