Remove listmanager
The file wasn't used, so any traces of listmanager.h or .c have been erased.
This commit is contained in:
@ -1,120 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
/*
|
|
||||||
* Copyright (c) 2016 MariaDB Corporation Ab
|
|
||||||
*
|
|
||||||
* Use of this software is governed by the Business Source License included
|
|
||||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
|
||||||
*
|
|
||||||
* Change Date: 2019-07-01
|
|
||||||
*
|
|
||||||
* On the date above, in accordance with the Business Source License, use
|
|
||||||
* of this software will be governed by version 2 or later of the General
|
|
||||||
* Public License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @file listmanager.h The List Manager header file
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @verbatim
|
|
||||||
* Revision History
|
|
||||||
*
|
|
||||||
* Date Who Description
|
|
||||||
* 20/04/2016 Martin Brampton Initial implementation
|
|
||||||
*
|
|
||||||
* @endverbatim
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <maxscale/cdefs.h>
|
|
||||||
#include <maxscale/spinlock.h>
|
|
||||||
#include <maxscale/debug.h>
|
|
||||||
|
|
||||||
MXS_BEGIN_DECLS
|
|
||||||
|
|
||||||
struct dcb;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The possible types of list that could be supported. At present, only
|
|
||||||
* LIST_TYPE_RECYCLABLE is fully tested.
|
|
||||||
*/
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
LIST_TYPE_SIMPLE, /* A simple linked list with pointer to last entry */
|
|
||||||
LIST_TYPE_RECYCLABLE, /* A simple linked list, entries are recycled */
|
|
||||||
LIST_TYPE_DOUBLE, /* A doubly linked list, next and previous */
|
|
||||||
} list_type_t;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The list entry structure
|
|
||||||
*
|
|
||||||
* Each list entry must have this format, but will typically be extended
|
|
||||||
* well beyond these items. The "previous" field is only required for
|
|
||||||
* a doubly linked list, LIST_TYPE_DOUBLE.
|
|
||||||
*
|
|
||||||
* The first data to be used with the list manager is the DCB. Note that
|
|
||||||
* the first few fields in the DCB structure correspond exactly to the
|
|
||||||
* fields in the list entry structure. The pointers used need to be cast
|
|
||||||
* as appropriate in order to be able to use the same data as either a DCB
|
|
||||||
* or a list entry.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
#define LIST_ENTRY_FIELDS \
|
|
||||||
skygw_chk_t list_entry_chk_top; \
|
|
||||||
struct list_entry *next; \
|
|
||||||
struct list_entry *previous; \
|
|
||||||
bool entry_is_in_use; \
|
|
||||||
bool entry_is_ready; \
|
|
||||||
skygw_chk_t list_entry_chk_tail;
|
|
||||||
|
|
||||||
typedef struct list_entry
|
|
||||||
{
|
|
||||||
LIST_ENTRY_FIELDS
|
|
||||||
} list_entry_t;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The list configuration structure
|
|
||||||
*
|
|
||||||
* This provides the basis for a list. It can be declared and initialised
|
|
||||||
* statically, for example in server/core/dcb.c. It includes an anchor
|
|
||||||
* pointer for the list, a pointer to the last entry in the list and the
|
|
||||||
* last entry that was found to be free and reused.
|
|
||||||
*
|
|
||||||
* The count tells us the current number of entries in live use, and maximum
|
|
||||||
* is the highest number ever observed in live use. The freecount is the
|
|
||||||
* number of entries currently free and ready for reuse. The entry_size is
|
|
||||||
* the actual size of the real entries, e.g. the DCB structure (NOT the size
|
|
||||||
* of the list entry structure).
|
|
||||||
*
|
|
||||||
* A spinlock is declared for use during list manipulation operations.
|
|
||||||
*/
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
list_type_t list_type;
|
|
||||||
size_t entry_size;
|
|
||||||
SPINLOCK list_lock;
|
|
||||||
list_entry_t *all_entries;
|
|
||||||
list_entry_t *last_entry;
|
|
||||||
list_entry_t *last_free;
|
|
||||||
int count;
|
|
||||||
int maximum;
|
|
||||||
int freecount;
|
|
||||||
int num_malloc;
|
|
||||||
} LIST_CONFIG;
|
|
||||||
|
|
||||||
void list_initialise(LIST_CONFIG *list_config, list_type_t type_of_list, size_t entry_size);
|
|
||||||
bool list_pre_alloc(LIST_CONFIG *list_config, int num_entries, void (*init_struct)(void *));
|
|
||||||
list_entry_t *list_find_free(LIST_CONFIG *list_config, void (*init_struct)(void *));
|
|
||||||
void dprintListStats(struct dcb *pdcb, LIST_CONFIG *list_config, const char *listname);
|
|
||||||
void list_free_entry (LIST_CONFIG *list_config, list_entry_t *to_be_freed);
|
|
||||||
list_entry_t *list_start_iteration(LIST_CONFIG *list_config);
|
|
||||||
list_entry_t *list_iterate(LIST_CONFIG *list_config, list_entry_t *current_entry);
|
|
||||||
void list_terminate_iteration_early(LIST_CONFIG *list_config, list_entry_t *current_entry);
|
|
||||||
bool list_is_entry_in_use(LIST_CONFIG *list_config, list_entry_t *to_be_found);
|
|
||||||
void list_add_to_end(LIST_CONFIG *list_config, list_entry_t *new_entry);
|
|
||||||
void list_map(LIST_CONFIG *list_config, bool (*callback)(void *, ...));
|
|
||||||
|
|
||||||
/* The following UNTESTED! */
|
|
||||||
list_entry_t *list_remove_first(LIST_CONFIG *list_config);
|
|
||||||
list_entry_t *list_remove_last(LIST_CONFIG *list_config);
|
|
||||||
|
|
||||||
MXS_END_DECLS
|
|
@ -379,8 +379,6 @@ void
|
|||||||
dcb_free_all_memory(DCB *dcb)
|
dcb_free_all_memory(DCB *dcb)
|
||||||
{
|
{
|
||||||
DCB_CALLBACK *cb_dcb;
|
DCB_CALLBACK *cb_dcb;
|
||||||
// TODO: Uncomment once listmanager code is in use
|
|
||||||
//ss_dassert(dcb->entry_is_in_use);
|
|
||||||
|
|
||||||
if (dcb->protocol && (!DCB_IS_CLONE(dcb)))
|
if (dcb->protocol && (!DCB_IS_CLONE(dcb)))
|
||||||
{
|
{
|
||||||
@ -1842,12 +1840,6 @@ void printAllDCBs()
|
|||||||
void
|
void
|
||||||
dprintOneDCB(DCB *pdcb, DCB *dcb)
|
dprintOneDCB(DCB *pdcb, DCB *dcb)
|
||||||
{
|
{
|
||||||
/* TODO: Uncomment once listmanager code is in use
|
|
||||||
if (false == dcb->entry_is_in_use)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
dcb_printf(pdcb, "DCB: %p\n", (void *)dcb);
|
dcb_printf(pdcb, "DCB: %p\n", (void *)dcb);
|
||||||
dcb_printf(pdcb, "\tDCB state: %s\n",
|
dcb_printf(pdcb, "\tDCB state: %s\n",
|
||||||
gw_dcb_state2string(dcb->state));
|
gw_dcb_state2string(dcb->state));
|
||||||
|
@ -1,451 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2016 MariaDB Corporation Ab
|
|
||||||
*
|
|
||||||
* Use of this software is governed by the Business Source License included
|
|
||||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
|
||||||
*
|
|
||||||
* Change Date: 2019-07-01
|
|
||||||
*
|
|
||||||
* On the date above, in accordance with the Business Source License, use
|
|
||||||
* of this software will be governed by version 2 or later of the General
|
|
||||||
* Public License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @file listmanager.c - Logic for list handling
|
|
||||||
*
|
|
||||||
* MaxScale contains a number of linked lists. This code attempts to provide
|
|
||||||
* standard functions for handling them. Initially, the main work has been
|
|
||||||
* on recyclable lists - lists of entries that use dynamically allocated
|
|
||||||
* memory but are reused rather than freed. Some functions are not fully
|
|
||||||
* tested - see comments.
|
|
||||||
*
|
|
||||||
* @verbatim
|
|
||||||
* Revision History
|
|
||||||
*
|
|
||||||
* Date Who Description
|
|
||||||
* 20/04/16 Martin Brampton Initial implementation
|
|
||||||
*
|
|
||||||
* @endverbatim
|
|
||||||
*/
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <maxscale/listmanager.h>
|
|
||||||
#include <maxscale/spinlock.h>
|
|
||||||
#include <maxscale/dcb.h>
|
|
||||||
#include <maxscale/log_manager.h>
|
|
||||||
#include <maxscale/alloc.h>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialise a list configuration.
|
|
||||||
*
|
|
||||||
* @param list_config Pointer to the configuration of the list to be initialised
|
|
||||||
* @param type_of_list Type of list to be initialised.
|
|
||||||
* @param entry_size The size of each list entry (typically from sizeof).
|
|
||||||
*
|
|
||||||
* @note This is only required if a list is configured at execution time
|
|
||||||
* rather than being declared and statically initialized.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
list_initialise(LIST_CONFIG *list_config, list_type_t type_of_list, size_t entry_size)
|
|
||||||
{
|
|
||||||
list_config->list_type = type_of_list;
|
|
||||||
list_config->all_entries = NULL;
|
|
||||||
list_config->last_entry = NULL;
|
|
||||||
list_config->last_free = NULL;
|
|
||||||
list_config->count = 0;
|
|
||||||
list_config->maximum = 0;
|
|
||||||
list_config->freecount = 0;
|
|
||||||
list_config->num_malloc = 0;
|
|
||||||
list_config->entry_size = entry_size;
|
|
||||||
spinlock_init(&list_config->list_lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Allocate memory for some initial list entries
|
|
||||||
*
|
|
||||||
* The caller must check the return value. If it is false, this most likely
|
|
||||||
* indicates a memory allocation failure, and the caller should act
|
|
||||||
* accordingly. (It could indicate that the requested number of entries
|
|
||||||
* was less than 1, but this is fairly unlikely).
|
|
||||||
*
|
|
||||||
* @param list_config Pointer to the configuration of the list to be initialised
|
|
||||||
* @param num_entries Number of list entries to be allocated
|
|
||||||
* @return true if memory was allocated, false if not (or num_entries < 1)
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
bool
|
|
||||||
list_pre_alloc(LIST_CONFIG *list_config, int num_entries, void (*init_struct)(void *))
|
|
||||||
{
|
|
||||||
uint8_t *entry_space;
|
|
||||||
bool result;
|
|
||||||
|
|
||||||
spinlock_acquire(&list_config->list_lock);
|
|
||||||
if (num_entries <= 0)
|
|
||||||
{
|
|
||||||
MXS_ERROR("Attempt to preallocate space for recyclable list asked for no entries");
|
|
||||||
result = false;
|
|
||||||
}
|
|
||||||
else if ((entry_space = (uint8_t *)MXS_CALLOC(num_entries, list_config->entry_size)) == NULL)
|
|
||||||
{
|
|
||||||
result = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
list_entry_t *first_new_entry = (list_entry_t *)entry_space;
|
|
||||||
list_entry_t *previous = first_new_entry;
|
|
||||||
|
|
||||||
for (int i = 1; i <= num_entries; i++)
|
|
||||||
{
|
|
||||||
if (init_struct)
|
|
||||||
{
|
|
||||||
init_struct((void *)previous);
|
|
||||||
}
|
|
||||||
previous->list_entry_chk_top = CHK_NUM_MANAGED_LIST;
|
|
||||||
previous->list_entry_chk_tail = CHK_NUM_MANAGED_LIST;
|
|
||||||
list_entry_t *next_entry = (list_entry_t *)((uint8_t *)previous + list_config->entry_size);
|
|
||||||
if (i < num_entries)
|
|
||||||
{
|
|
||||||
previous->next = next_entry;
|
|
||||||
previous = next_entry;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
previous->next = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
list_config->freecount += num_entries;
|
|
||||||
list_add_to_end(list_config, first_new_entry);
|
|
||||||
list_config->last_entry = previous;
|
|
||||||
list_config->last_free = first_new_entry;
|
|
||||||
result = true;
|
|
||||||
}
|
|
||||||
spinlock_release(&list_config->list_lock);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Find a free list entry or allocate memory for a new one.
|
|
||||||
*
|
|
||||||
* This routine looks to see whether there are free entries.
|
|
||||||
* If not, new memory is allocated, if possible, and the new entry is added to
|
|
||||||
* the list of all entries.
|
|
||||||
*
|
|
||||||
* @param Pointer to the list configuration structure
|
|
||||||
* @return An available entry or NULL if none could be found or created.
|
|
||||||
*/
|
|
||||||
list_entry_t *
|
|
||||||
list_find_free(LIST_CONFIG *list_config, void (*init_struct)(void *))
|
|
||||||
{
|
|
||||||
list_entry_t *available_entry;
|
|
||||||
|
|
||||||
spinlock_acquire(&list_config->list_lock);
|
|
||||||
if (list_config->freecount <= 0)
|
|
||||||
{
|
|
||||||
/* No free entries, need to allocate a new one */
|
|
||||||
if ((available_entry = MXS_CALLOC(1, list_config->entry_size)) == NULL)
|
|
||||||
{
|
|
||||||
spinlock_release(&list_config->list_lock);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
list_config->num_malloc++;
|
|
||||||
|
|
||||||
if (init_struct)
|
|
||||||
{
|
|
||||||
init_struct((void *)available_entry);
|
|
||||||
}
|
|
||||||
available_entry->list_entry_chk_top = CHK_NUM_MANAGED_LIST;
|
|
||||||
available_entry->list_entry_chk_tail = CHK_NUM_MANAGED_LIST;
|
|
||||||
available_entry->next = NULL;
|
|
||||||
list_add_to_end(list_config, available_entry);
|
|
||||||
}
|
|
||||||
/* Starting at the last place a free DCB was found, loop through the */
|
|
||||||
/* list of DCBs searching for one that is not in use. */
|
|
||||||
else
|
|
||||||
{
|
|
||||||
list_entry_t *next_in_list;
|
|
||||||
int loopcount = 0;
|
|
||||||
|
|
||||||
while (list_config->last_free->entry_is_in_use)
|
|
||||||
{
|
|
||||||
list_config->last_free = list_config->last_free->next;
|
|
||||||
if (NULL == list_config->last_free)
|
|
||||||
{
|
|
||||||
loopcount++;
|
|
||||||
ss_dassert(loopcount == 1);
|
|
||||||
if (loopcount > 1)
|
|
||||||
{
|
|
||||||
/* Shouldn't need to loop round more than once */
|
|
||||||
MXS_ERROR("Find free list entry failed to find when count positive");
|
|
||||||
spinlock_release(&list_config->list_lock);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
list_config->last_free = list_config->all_entries;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
list_config->freecount--;
|
|
||||||
available_entry = list_config->last_free;
|
|
||||||
/* Clear the old data, then reset the list forward link */
|
|
||||||
next_in_list = available_entry->next;
|
|
||||||
if (init_struct)
|
|
||||||
{
|
|
||||||
init_struct((void *)available_entry);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
memset(available_entry, 0, list_config->entry_size);
|
|
||||||
}
|
|
||||||
available_entry->list_entry_chk_top = CHK_NUM_MANAGED_LIST;
|
|
||||||
available_entry->list_entry_chk_tail = CHK_NUM_MANAGED_LIST;
|
|
||||||
available_entry->next = next_in_list;
|
|
||||||
}
|
|
||||||
list_config->count++;
|
|
||||||
if (list_config->count > list_config->maximum)
|
|
||||||
{
|
|
||||||
list_config->maximum = list_config->count;
|
|
||||||
}
|
|
||||||
available_entry->entry_is_in_use = true;
|
|
||||||
spinlock_release(&list_config->list_lock);
|
|
||||||
return available_entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Display information about a recyclable list
|
|
||||||
*
|
|
||||||
* Should be called from a module that handles one specific list, passing
|
|
||||||
* the name for the list as well as the print DCB and the list config.
|
|
||||||
*
|
|
||||||
* @param Pointer to the print DCB
|
|
||||||
* @param List configuration pointer, the list to be displayed
|
|
||||||
* @param Name for the list
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
dprintListStats(DCB *pdcb, LIST_CONFIG *list_config, const char *listname)
|
|
||||||
{
|
|
||||||
dcb_printf(pdcb, "Recyclable list statistics\n");
|
|
||||||
dcb_printf(pdcb, "--------------------------\n");
|
|
||||||
dcb_printf(pdcb, "Name of list: %s\n", listname);
|
|
||||||
dcb_printf(pdcb, "Size of entries: %zu\n", list_config->entry_size);
|
|
||||||
dcb_printf(pdcb, "Currently in use: %d\n", list_config->count);
|
|
||||||
dcb_printf(pdcb, "Maximum ever used at once: %d\n", list_config->maximum);
|
|
||||||
dcb_printf(pdcb, "Currently free for reuse: %d\n", list_config->freecount);
|
|
||||||
dcb_printf(pdcb, "Total in use + free: %d\n",
|
|
||||||
list_config->freecount + list_config->count);
|
|
||||||
dcb_printf(pdcb, "Number of memory allocations: %d\n", list_config->num_malloc);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Dispose of a list entry by making it available for reuse.
|
|
||||||
*
|
|
||||||
* Within spinlock control, the entry is marked not in use and the
|
|
||||||
* counts are adjusted.
|
|
||||||
*
|
|
||||||
* @param Pointer to the list configuration structure
|
|
||||||
* @param List entry pointer, the item to be "freed"
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
list_free_entry(LIST_CONFIG *list_config, list_entry_t *to_be_freed)
|
|
||||||
{
|
|
||||||
spinlock_acquire(&list_config->list_lock);
|
|
||||||
to_be_freed->entry_is_in_use = false;
|
|
||||||
list_config->freecount++;
|
|
||||||
list_config->count--;
|
|
||||||
spinlock_release(&list_config->list_lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Find out whether a pointer points to a valid list entry
|
|
||||||
*
|
|
||||||
* Search the list for the given entry, under spinlock control.
|
|
||||||
*
|
|
||||||
* @param Pointer to the list configuration structure
|
|
||||||
* @param Pointer to be searched for
|
|
||||||
* @return True if the pointer is in the list and it is in use
|
|
||||||
*/
|
|
||||||
bool
|
|
||||||
list_is_entry_in_use(LIST_CONFIG *list_config, list_entry_t *to_be_found)
|
|
||||||
{
|
|
||||||
list_entry_t *entry;
|
|
||||||
|
|
||||||
spinlock_acquire(&list_config->list_lock);
|
|
||||||
entry = list_config->all_entries;
|
|
||||||
while (entry && to_be_found != entry)
|
|
||||||
{
|
|
||||||
entry = entry->next;
|
|
||||||
}
|
|
||||||
spinlock_release(&list_config->list_lock);
|
|
||||||
|
|
||||||
return (entry && entry->entry_is_in_use);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Invoke a callback for every active member of list
|
|
||||||
*
|
|
||||||
* The list is locked, list entries that are in use are successively
|
|
||||||
* submitted to the callback function. The list entry is supplied to the
|
|
||||||
* callback function as the first parameters, followed by whatever other
|
|
||||||
* parameters have been passed to list_map. The process will continue so
|
|
||||||
* long as the callback function returns true, and will terminate either
|
|
||||||
* at the end of the list or when the callback function returns false.
|
|
||||||
*
|
|
||||||
* Code to be developed.
|
|
||||||
*
|
|
||||||
* @param Pointer to the list configuration structure
|
|
||||||
* @param Pointer to the callback function
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
list_map(LIST_CONFIG *list_config, bool (*callback)(void *, ...))
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Start to iterate over a list
|
|
||||||
*
|
|
||||||
* The list is locked, and the first entry returned to the caller
|
|
||||||
*
|
|
||||||
* @param Pointer to the list configuration structure
|
|
||||||
* @return Pointer to the first entry in the list
|
|
||||||
*/
|
|
||||||
list_entry_t *
|
|
||||||
list_start_iteration(LIST_CONFIG *list_config)
|
|
||||||
{
|
|
||||||
spinlock_acquire(&list_config->list_lock);
|
|
||||||
return list_config->all_entries;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Iterate over a list from a given point
|
|
||||||
*
|
|
||||||
* The list is assumed locked through list_start_iteration having been
|
|
||||||
* called. The next entry that is currently in use is returned to the caller.
|
|
||||||
* If the end of the list is reached, the spinlock is freed.
|
|
||||||
*
|
|
||||||
* @param Pointer to the list configuration structure
|
|
||||||
* @param Pointer to the entry to move forward from
|
|
||||||
* @return The next item in the list, or NULL if reached the end
|
|
||||||
*/
|
|
||||||
list_entry_t *
|
|
||||||
list_iterate(LIST_CONFIG *list_config, list_entry_t *current_entry)
|
|
||||||
{
|
|
||||||
list_entry_t *next_entry = current_entry->next;
|
|
||||||
while (next_entry && !(next_entry->entry_is_in_use && next_entry->entry_is_ready))
|
|
||||||
{
|
|
||||||
next_entry = next_entry->next;
|
|
||||||
}
|
|
||||||
if (NULL == next_entry)
|
|
||||||
{
|
|
||||||
spinlock_release(&list_config->list_lock);
|
|
||||||
}
|
|
||||||
return next_entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Terminate list iteration before reaching the end
|
|
||||||
*
|
|
||||||
* The list is assumed locked through list_start_iteration having been
|
|
||||||
* called, unless the last item is NULL, in which case it is assumed that
|
|
||||||
* the iteration had already reached the end of the list. If this is not
|
|
||||||
* the case, then the spinlock is released.
|
|
||||||
*
|
|
||||||
* @param Pointer to the list configuration structure
|
|
||||||
* @param Pointer to the entry last reached in the iteration
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
list_terminate_iteration_early(LIST_CONFIG *list_config, list_entry_t *current_entry)
|
|
||||||
{
|
|
||||||
if (current_entry)
|
|
||||||
{
|
|
||||||
spinlock_release(&list_config->list_lock);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a new item to the end of a list.
|
|
||||||
*
|
|
||||||
* Must be called with the list lock held.
|
|
||||||
*
|
|
||||||
* A pointer, last_entry, is held to find the end of the list, and the new entry
|
|
||||||
* is linked to the end of the list. The pointer, last_free, that is used to
|
|
||||||
* search for a free entry is initialised if not already set. There cannot be
|
|
||||||
* any free entries until this routine has been called at least once.
|
|
||||||
*
|
|
||||||
* @param list_config The configuration of the list.
|
|
||||||
* @param new_entry The new entry to be added to the end of the list
|
|
||||||
*
|
|
||||||
* @note UNTESTED for simple or doubly linked lists, currently used
|
|
||||||
* internally for recyclable lists.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
list_add_to_end(LIST_CONFIG *list_config, list_entry_t *new_entry)
|
|
||||||
{
|
|
||||||
if (NULL == list_config->all_entries)
|
|
||||||
{
|
|
||||||
list_config->all_entries = new_entry;
|
|
||||||
if (LIST_TYPE_DOUBLE == list_config->list_type)
|
|
||||||
{
|
|
||||||
new_entry->previous = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
list_config->last_entry->next = new_entry;
|
|
||||||
if (LIST_TYPE_DOUBLE == list_config->list_type)
|
|
||||||
{
|
|
||||||
new_entry->previous = list_config->last_entry;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
list_config->last_entry = new_entry;
|
|
||||||
if (NULL == list_config->last_free)
|
|
||||||
{
|
|
||||||
list_config->last_free = new_entry;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief the list entry removed from the start of the list
|
|
||||||
*
|
|
||||||
* Must be called with the list lock held.
|
|
||||||
*
|
|
||||||
* @return The first list entry or NULL if the list is empty.
|
|
||||||
*
|
|
||||||
* @note UNTESTED! Intended for use on simple or doubly linked lists.
|
|
||||||
*/
|
|
||||||
list_entry_t *
|
|
||||||
list_remove_first(LIST_CONFIG *list_config)
|
|
||||||
{
|
|
||||||
list_entry_t *first_in_list = NULL;
|
|
||||||
if (list_config->all_entries)
|
|
||||||
{
|
|
||||||
first_in_list = list_config->all_entries;
|
|
||||||
list_config->all_entries = first_in_list->next;
|
|
||||||
}
|
|
||||||
return first_in_list;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Return the list entry removed from the end of the list
|
|
||||||
*
|
|
||||||
* Must be called with the list lock held.
|
|
||||||
*
|
|
||||||
* @return The last list entry or NULL if the list is empty.
|
|
||||||
*
|
|
||||||
* @note UNTESTED! Intended for use only with doubly linked lists.
|
|
||||||
*/
|
|
||||||
list_entry_t *
|
|
||||||
list_remove_last(LIST_CONFIG *list_config)
|
|
||||||
{
|
|
||||||
list_entry_t *last_in_list = NULL;
|
|
||||||
if (list_config->list_type != LIST_TYPE_DOUBLE)
|
|
||||||
{
|
|
||||||
MXS_ERROR("Attempt to remove the last entry in a list that is not doubly linked");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
if (list_config->all_entries)
|
|
||||||
{
|
|
||||||
last_in_list = list_config->last_entry;
|
|
||||||
list_config->last_entry = last_in_list->previous;
|
|
||||||
}
|
|
||||||
return last_in_list;
|
|
||||||
}
|
|
@ -60,7 +60,6 @@
|
|||||||
#include <maxscale/protocol/mysql.h>
|
#include <maxscale/protocol/mysql.h>
|
||||||
#include <maxscale/housekeeper.h>
|
#include <maxscale/housekeeper.h>
|
||||||
#include <maxscale/alloc.h>
|
#include <maxscale/alloc.h>
|
||||||
#include <maxscale/listmanager.h>
|
|
||||||
|
|
||||||
#define MYSQL_COM_QUIT 0x01
|
#define MYSQL_COM_QUIT 0x01
|
||||||
#define MYSQL_COM_INITDB 0x02
|
#define MYSQL_COM_INITDB 0x02
|
||||||
|
@ -70,7 +70,6 @@
|
|||||||
#include <maxscale/adminusers.h>
|
#include <maxscale/adminusers.h>
|
||||||
#include <debugcli.h>
|
#include <debugcli.h>
|
||||||
#include <maxscale/housekeeper.h>
|
#include <maxscale/housekeeper.h>
|
||||||
#include <maxscale/listmanager.h>
|
|
||||||
#include <maxscale/maxscale.h>
|
#include <maxscale/maxscale.h>
|
||||||
#include <maxscale/version.h>
|
#include <maxscale/version.h>
|
||||||
#include <maxscale/log_manager.h>
|
#include <maxscale/log_manager.h>
|
||||||
|
Reference in New Issue
Block a user