Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 2000 - 2005 Pekka Riikonen
+ Copyright (C) 2000 - 2007 Pekka Riikonen
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
* DESCRIPTION
*
* SILC Dynamic List API can be used to add opaque contexts to list that
- * will automatically allocate list entries. Normal SILC List API cannot
+ * will automatically allocate list entries. The simpler SilcList cannot
* be used for this purpose because in that case the context passed to the
* list must be defined as list structure already. This is not the case in
- * SilcDList.
+ * SilcDList. But SilcDList is a bit slower than SilcList because it
+ * requires memory allocation when adding new entries to the list.
*
- * This is slower than SilcList because this requires one extra memory
- * allocation when adding new entries to the list. The context is probably
- * allocated already and the new list entry requires one additional memory
- * allocation. The memory allocation and freeing is done automatically in
- * the API and does not show to the caller.
+ * SILC Dynamic List is not thread-safe. If the same list context must be
+ * used in multithreaded environment concurrency control must be employed.
+ *
+ * EXAMPLE
+ *
+ * SilcDList list = silc_dlist_init();
+ *
+ * silc_dlist_add(list, entry1);
+ * silc_dlist_add(list, entry2);
+ *
+ * // Traverse the list from the beginning to the end
+ * silc_dlist_start(list)
+ * while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
+ * ...
+ * }
+ *
+ * silc_dlist_uninit(list);
*
***/
* Application defines this object and adds contexts to this list with
* Dynamic List Interface functions.
*
- * SOURCE
- */
+ ***/
typedef struct SilcDListStruct {
+ SilcStack stack;
SilcList list;
void *current;
void *prev;
} *SilcDList;
-/***/
/* SilcDListEntry structure, one entry in the list. This MUST NOT be used
directly by the application. */
*
* DESCRIPTION
*
- * Initializes SilcDList.
+ * Initializes SilcDList. Returns the SilcDList context or NULL if system
+ * is out of memory.
*
***/
list = (SilcDList)silc_malloc(sizeof(*list));
if (!list)
return NULL;
+ list->stack = list->current = list->prev = NULL;
+ silc_list_init_prev(list->list, struct SilcDListEntryStruct, next, prev);
+
+ return list;
+}
+
+/****f* silcutil/SilcDListAPI/silc_dlist_sinit
+ *
+ * SYNOPSIS
+ *
+ * static inline
+ * SilcDList silc_dlist_sinit(SilcStack stack);
+ *
+ * DESCRIPTION
+ *
+ * Initializes SilcDList. Returns the SilcDList context or NULL on error.
+ * This is same as silc_dlist_init but allocates the memory from `stack'
+ * if `stack' is non-NULL.
+ *
+ ***/
+
+static inline
+SilcDList silc_dlist_sinit(SilcStack stack)
+{
+ SilcDList list;
+
+ if (stack)
+ stack = silc_stack_alloc(0, stack);
+ list = (SilcDList)silc_smalloc(stack, sizeof(*list));
+ if (!list) {
+ silc_stack_free(stack);
+ return NULL;
+ }
+ list->stack = stack;
list->current = list->prev = NULL;
silc_list_init_prev(list->list, struct SilcDListEntryStruct, next, prev);
* DESCRIPTION
*
* Uninits and frees all memory. Must be called to free memory. Does NOT
- * free the contexts saved by caller.
+ * free the contexts saved by caller. If the silc_dlist_sinit was used
+ * with SilcStack this will release all memory allocated by the SilcDList
+ * back to the SilcStack.
*
***/
{
if (list) {
SilcDListEntry e;
+ SilcStack stack = list->stack;
silc_list_start(list->list);
while ((e = (SilcDListEntry)silc_list_get(list->list)) != SILC_LIST_END) {
silc_list_del(list->list, e);
- silc_free(e);
+ silc_sfree(stack, e);
}
- silc_free(list);
+ silc_sfree(stack, list);
+ silc_stack_free(stack);
}
}
static inline
SilcBool silc_dlist_add(SilcDList list, void *context)
{
- SilcDListEntry e = (SilcDListEntry)silc_malloc(sizeof(*e));
- if (!e)
+ SilcDListEntry e = (SilcDListEntry)silc_smalloc(list->stack, sizeof(*e));
+ if (silc_unlikely(!e))
return FALSE;
e->context = context;
silc_list_add(list->list, e);
static inline
SilcBool silc_dlist_insert(SilcDList list, void *context)
{
- SilcDListEntry e = (SilcDListEntry)silc_malloc(sizeof(*e));
- if (!e)
+ SilcDListEntry e = (SilcDListEntry)silc_smalloc(list->stack, sizeof(*e));
+ if (silc_unlikely(!e))
return FALSE;
e->context = context;
silc_list_insert(list->list, list->prev, e);
* SYNOPSIS
*
* static inline
- * void silc_dlist_del(SilcDList list, void *context);
+ * void silc_dlist_del(SilcDList list, void *entry);
*
* DESCRIPTION
*
- * Remove entry from the list. Returns < 0 on error, 0 otherwise.
+ * Remove entry from the list.
*
***/
static inline
-void silc_dlist_del(SilcDList list, void *context)
+void silc_dlist_del(SilcDList list, void *entry)
{
SilcDListEntry e;
silc_list_start(list->list);
while ((e = (SilcDListEntry)silc_list_get(list->list)) != SILC_LIST_END) {
- if (e->context == context) {
+ if (e->context == entry) {
silc_list_del(list->list, e);
#if defined(SILC_DEBUG)
memset(e, 'F', sizeof(*e));
list->current = NULL;
if (list->prev == e)
list->prev = NULL;
- silc_free(e);
+ silc_sfree(list->stack, e);
break;
}
}