 396b81f336
			
		
	
	396b81f336
	
	
	
		
			
			The internal header directory conflicted with in-source builds causing a build failure. This is fixed by renaming the internal header directory to something other than maxscale. The renaming pointed out a few problems in a couple of source files that appeared to include internal headers when the headers were in fact public headers. Fixed maxctrl in-source builds by making the copying of the sources optional.
		
			
				
	
	
		
			418 lines
		
	
	
		
			9.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			418 lines
		
	
	
		
			9.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
|  * 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/bsl11.
 | |
|  *
 | |
|  * Change Date: 2020-01-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.
 | |
|  */
 | |
| 
 | |
| #include "internal/mlist.h"
 | |
| #include <maxscale/alloc.h>
 | |
| 
 | |
| static void mlist_free_memory(mlist_t* ml, char* name);
 | |
| static mlist_node_t* mlist_node_init(void* data, mlist_cursor_t* cursor);
 | |
| //static mlist_node_t* mlist_node_get_next(mlist_node_t* curr_node);
 | |
| //static mlist_node_t* mlist_get_first(mlist_t* list);
 | |
| //static mlist_cursor_t* mlist_get_cursor(mlist_t* list);
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * @node Cut off nodes of the list.
 | |
|  *
 | |
|  * Parameters:
 | |
|  * @param ml - <usage>
 | |
|  *          <description>
 | |
|  *
 | |
|  * @return Pointer to the first of the detached nodes.
 | |
|  *
 | |
|  *
 | |
|  * @details (write detailed description here)
 | |
|  *
 | |
|  */
 | |
| mlist_node_t* mlist_detach_nodes(mlist_t* ml)
 | |
| {
 | |
|     mlist_node_t* node;
 | |
|     CHK_MLIST(ml);
 | |
| 
 | |
|     node = ml->mlist_first;
 | |
|     ml->mlist_first = NULL;
 | |
|     ml->mlist_last = NULL;
 | |
|     ml->mlist_nodecount = 0;
 | |
|     return node;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * @node Create a list with rwlock and optional read-only cursor
 | |
|  *
 | |
|  * Parameters:
 | |
|  * @param listp - <usage>
 | |
|  *          <description>
 | |
|  *
 | |
|  * @param cursor - <usage>
 | |
|  *          <description>
 | |
|  *
 | |
|  * @param name - <usage>
 | |
|  *          <description>
 | |
|  *
 | |
|  * @return Address of mlist_t struct.
 | |
|  *
 | |
|  *
 | |
|  * @details Cursor must protect its reads with read lock, and after
 | |
|  * acquiring read lock reader must check whether the list is deleted
 | |
|  * (mlist_deleted).
 | |
|  *
 | |
|  */
 | |
| mlist_t* mlist_init(mlist_t* listp, mlist_cursor_t** cursor, char* name,
 | |
|                     void (*datadel)(void*), int maxnodes)
 | |
| {
 | |
|     mlist_cursor_t* c;
 | |
|     mlist_t* list;
 | |
| 
 | |
|     if (cursor != NULL)
 | |
|     {
 | |
|         ss_dassert(*cursor == NULL);
 | |
|     }
 | |
|     /** listp is not NULL if caller wants flat list */
 | |
|     if (listp == NULL)
 | |
|     {
 | |
|         list = (mlist_t*) MXS_CALLOC(1, sizeof (mlist_t));
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         /** Caller wants list flat, memory won't be freed */
 | |
|         list = listp;
 | |
|         list->mlist_flat = true;
 | |
|     }
 | |
|     ss_dassert(list != NULL);
 | |
| 
 | |
|     if (list == NULL)
 | |
|     {
 | |
|         mlist_free_memory(list, name);
 | |
|         goto return_list;
 | |
|     }
 | |
|     list->mlist_chk_top = CHK_NUM_MLIST;
 | |
|     list->mlist_chk_tail = CHK_NUM_MLIST;
 | |
|     /** Set size limit for list. 0 means unlimited */
 | |
|     list->mlist_nodecount_max = maxnodes;
 | |
|     /** Set data deletion callback fun */
 | |
|     list->mlist_datadel = datadel;
 | |
| 
 | |
|     if (name != NULL)
 | |
|     {
 | |
|         list->mlist_name = name;
 | |
|     }
 | |
|     /** Create mutex, return NULL if fails. */
 | |
|     if (simple_mutex_init(&list->mlist_mutex, "writebuf mutex") == NULL)
 | |
|     {
 | |
|         ss_dfprintf(stderr, "* Creating rwlock for mlist failed\n");
 | |
|         mlist_free_memory(list, name);
 | |
|         list = NULL;
 | |
|         goto return_list;
 | |
|     }
 | |
| 
 | |
|     /** Create cursor for reading the list */
 | |
|     if (cursor != NULL)
 | |
|     {
 | |
|         c = mlist_cursor_init(list);
 | |
| 
 | |
|         if (c == NULL)
 | |
|         {
 | |
|             simple_mutex_done(&list->mlist_mutex);
 | |
|             mlist_free_memory(list, name);
 | |
|             list = NULL;
 | |
|             goto return_list;
 | |
|         }
 | |
|         CHK_MLIST_CURSOR(c);
 | |
|         *cursor = c;
 | |
|     }
 | |
|     list->mlist_versno = 2; /*< vresno != 0 means that list is initialized */
 | |
|     CHK_MLIST(list);
 | |
| 
 | |
| return_list:
 | |
|     return list;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * @node Free mlist memory allocations. name must be explicitly
 | |
|  * set if mlist has one.
 | |
|  *
 | |
|  * Parameters:
 | |
|  * @param ml - <usage>
 | |
|  *          <description>
 | |
|  *
 | |
|  * @param name - <usage>
 | |
|  *          <description>
 | |
|  *
 | |
|  * @return void
 | |
|  *
 | |
|  *
 | |
|  * @details (write detailed description here)
 | |
|  *
 | |
|  */
 | |
| static void mlist_free_memory(mlist_t* ml, char* name)
 | |
| {
 | |
|     mlist_node_t* node;
 | |
| 
 | |
|     /** name */
 | |
|     if (name != NULL)
 | |
|     {
 | |
|         MXS_FREE(name);
 | |
|     }
 | |
|     if (ml != NULL)
 | |
|     {
 | |
|         /** list data */
 | |
|         while (ml->mlist_first != NULL)
 | |
|         {
 | |
|             /** Scan list and free nodes and data inside nodes */
 | |
|             node = ml->mlist_first->mlnode_next;
 | |
|             mlist_node_done(ml->mlist_first);
 | |
|             ml->mlist_first = node;
 | |
|         }
 | |
| 
 | |
|         /** list structure */
 | |
|         if (!ml->mlist_flat)
 | |
|         {
 | |
|             MXS_FREE(ml);
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| void* mlist_node_get_data(mlist_node_t* node)
 | |
| {
 | |
|     CHK_MLIST_NODE(node);
 | |
|     return node->mlnode_data;
 | |
| }
 | |
| 
 | |
| void mlist_node_done(mlist_node_t* n)
 | |
| {
 | |
|     CHK_MLIST_NODE(n);
 | |
|     if (n->mlnode_data != NULL)
 | |
|     {
 | |
|         if (n->mlnode_list->mlist_datadel != NULL)
 | |
|         {
 | |
|             (n->mlnode_list->mlist_datadel(n->mlnode_data));
 | |
|         }
 | |
|         MXS_FREE(n->mlnode_data);
 | |
|     }
 | |
|     MXS_FREE(n);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * @node Mark list as deleted and free the memory.
 | |
|  *
 | |
|  * Parameters:
 | |
|  * @param list - <usage>
 | |
|  *          <description>
 | |
|  *
 | |
|  * @return void
 | |
|  *
 | |
|  *
 | |
|  * @details (write detailed description here)
 | |
|  *
 | |
|  */
 | |
| void mlist_done(mlist_t* list)
 | |
| {
 | |
|     CHK_MLIST(list);
 | |
|     simple_mutex_lock(&list->mlist_mutex, true);
 | |
|     list->mlist_deleted = true;
 | |
|     simple_mutex_unlock(&list->mlist_mutex);
 | |
|     simple_mutex_done(&list->mlist_mutex);
 | |
|     mlist_free_memory(list, list->mlist_name);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * @node Adds data to list by allocating node for it. Checks list size limit.
 | |
|  *
 | |
|  * Parameters:
 | |
|  * @param list - <usage>
 | |
|  *          <description>
 | |
|  *
 | |
|  * @param data - <usage>
 | |
|  *          <description>
 | |
|  *
 | |
|  * @return true, if succeed, false, if list had node limit and it is full.
 | |
|  *
 | |
|  *
 | |
|  * @details (write detailed description here)
 | |
|  *
 | |
|  */
 | |
| bool mlist_add_data_nomutex(mlist_t* list, void* data)
 | |
| {
 | |
|     bool succp;
 | |
| 
 | |
|     succp = mlist_add_node_nomutex(list, mlist_node_init(data, NULL));
 | |
| 
 | |
|     return succp;
 | |
| }
 | |
| 
 | |
| static mlist_node_t* mlist_node_init(void* data, mlist_cursor_t* cursor)
 | |
| {
 | |
|     mlist_node_t* node;
 | |
| 
 | |
|     node = (mlist_node_t*) MXS_CALLOC(1, sizeof (mlist_node_t));
 | |
|     MXS_ABORT_IF_NULL(node);
 | |
|     node->mlnode_chk_top = CHK_NUM_MLIST_NODE;
 | |
|     node->mlnode_chk_tail = CHK_NUM_MLIST_NODE;
 | |
|     node->mlnode_data = data;
 | |
|     CHK_MLIST_NODE(node);
 | |
| 
 | |
|     if (cursor != NULL)
 | |
|     {
 | |
|         cursor->mlcursor_pos = node;
 | |
|     }
 | |
| 
 | |
|     return node;
 | |
| }
 | |
| 
 | |
| mlist_node_t* mlist_detach_first(mlist_t* ml)
 | |
| {
 | |
|     mlist_node_t* node;
 | |
| 
 | |
|     CHK_MLIST(ml);
 | |
|     node = ml->mlist_first;
 | |
|     CHK_MLIST_NODE(node);
 | |
|     ml->mlist_first = node->mlnode_next;
 | |
|     node->mlnode_next = NULL;
 | |
| 
 | |
|     ml->mlist_nodecount -= 1;
 | |
|     if (ml->mlist_nodecount == 0)
 | |
|     {
 | |
|         ml->mlist_last = NULL;
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         CHK_MLIST_NODE(ml->mlist_first);
 | |
|     }
 | |
|     CHK_MLIST(ml);
 | |
| 
 | |
|     return (node);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * @node Add new node to end of list if there is space for it.
 | |
|  *
 | |
|  * Parameters:
 | |
|  * @param list - <usage>
 | |
|  *          <description>
 | |
|  *
 | |
|  * @param newnode - <usage>
 | |
|  *          <description>
 | |
|  *
 | |
|  * @param add_last - <usage>
 | |
|  *          <description>
 | |
|  *
 | |
|  * @return true, if succeede, false, if list size limit was exceeded.
 | |
|  *
 | |
|  *
 | |
|  * @details (write detailed description here)
 | |
|  *
 | |
|  */
 | |
| bool mlist_add_node_nomutex(mlist_t* list, mlist_node_t* newnode)
 | |
| {
 | |
|     bool succp = false;
 | |
| 
 | |
|     CHK_MLIST(list);
 | |
|     CHK_MLIST_NODE(newnode);
 | |
|     ss_dassert(!list->mlist_deleted);
 | |
| 
 | |
|     /** List is full already. */
 | |
|     if (list->mlist_nodecount == list->mlist_nodecount_max)
 | |
|     {
 | |
|         goto return_succp;
 | |
|     }
 | |
|     /** Find location for new node */
 | |
|     if (list->mlist_last != NULL)
 | |
|     {
 | |
|         ss_dassert(!list->mlist_last->mlnode_deleted);
 | |
|         CHK_MLIST_NODE(list->mlist_last);
 | |
|         CHK_MLIST_NODE(list->mlist_first);
 | |
|         ss_dassert(list->mlist_last->mlnode_next == NULL);
 | |
|         list->mlist_last->mlnode_next = newnode;
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         list->mlist_first = newnode;
 | |
|     }
 | |
|     list->mlist_last = newnode;
 | |
|     newnode->mlnode_list = list;
 | |
|     list->mlist_nodecount += 1;
 | |
|     succp = true;
 | |
| return_succp:
 | |
|     CHK_MLIST(list);
 | |
|     return succp;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * mlist_cursor_t
 | |
|  */
 | |
| mlist_cursor_t* mlist_cursor_init(mlist_t* list)
 | |
| {
 | |
|     CHK_MLIST(list);
 | |
|     mlist_cursor_t* c;
 | |
| 
 | |
|     /** acquire shared lock to the list */
 | |
|     simple_mutex_lock(&list->mlist_mutex, true);
 | |
| 
 | |
|     c = (mlist_cursor_t *) MXS_CALLOC(1, sizeof (mlist_cursor_t));
 | |
| 
 | |
|     if (c == NULL)
 | |
|     {
 | |
|         simple_mutex_unlock(&list->mlist_mutex);
 | |
|         goto return_cursor;
 | |
|     }
 | |
|     c->mlcursor_chk_top = CHK_NUM_MLIST_CURSOR;
 | |
|     c->mlcursor_chk_tail = CHK_NUM_MLIST_CURSOR;
 | |
|     c->mlcursor_list = list;
 | |
| 
 | |
|     /** Set cursor position if list is not empty */
 | |
|     if (list->mlist_first != NULL)
 | |
|     {
 | |
|         c->mlcursor_pos = list->mlist_first;
 | |
|     }
 | |
|     simple_mutex_unlock(&list->mlist_mutex);
 | |
| 
 | |
|     CHK_MLIST_CURSOR(c);
 | |
| 
 | |
| return_cursor:
 | |
|     return c;
 | |
| }
 | |
| 
 | |
| void* mlist_cursor_get_data_nomutex(mlist_cursor_t* mc)
 | |
| {
 | |
|     CHK_MLIST_CURSOR(mc);
 | |
|     return (mc->mlcursor_pos->mlnode_data);
 | |
| }
 | |
| 
 | |
| bool mlist_cursor_move_to_first(mlist_cursor_t* mc)
 | |
| {
 | |
|     bool succp = false;
 | |
|     mlist_t* list;
 | |
| 
 | |
|     CHK_MLIST_CURSOR(mc);
 | |
|     list = mc->mlcursor_list;
 | |
|     CHK_MLIST(list);
 | |
|     simple_mutex_lock(&list->mlist_mutex, true);
 | |
| 
 | |
|     if (mc->mlcursor_list->mlist_deleted)
 | |
|     {
 | |
|         simple_mutex_unlock(&list->mlist_mutex);
 | |
|         return false;
 | |
|     }
 | |
|     /** Set position point to first node */
 | |
|     mc->mlcursor_pos = list->mlist_first;
 | |
| 
 | |
|     if (mc->mlcursor_pos != NULL)
 | |
|     {
 | |
|         CHK_MLIST_NODE(mc->mlcursor_pos);
 | |
|         succp = true;
 | |
|     }
 | |
|     simple_mutex_unlock(&list->mlist_mutex);
 | |
|     return succp;
 | |
| }
 |