Make mlist a separate component.
Mlist is now made available as a separate component instead of being a part of skygw_utils.
This commit is contained in:
@ -37,24 +37,12 @@
|
||||
#include <random_jkiss.h>
|
||||
#include <pcre2.h>
|
||||
|
||||
#if defined(MLIST)
|
||||
|
||||
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);
|
||||
|
||||
#endif /* MLIST */
|
||||
|
||||
static bool file_write_header(skygw_file_t* file);
|
||||
static void simple_mutex_free_memory(simple_mutex_t* sm);
|
||||
static void mlist_free_memory(mlist_t* ml, char* name);
|
||||
static void thread_free_memory(skygw_thread_t* th, char* name);
|
||||
/** End of static function declarations */
|
||||
|
||||
/** mutexed list, mlist */
|
||||
|
||||
#if defined(MLIST)
|
||||
/** mutexed list */
|
||||
|
||||
int skygw_rwlock_rdlock(skygw_rwlock_t* rwlock)
|
||||
{
|
||||
@ -172,404 +160,6 @@ return_err:
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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*) 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)
|
||||
{
|
||||
fprintf(stderr, "* Allocating memory for mlist failed\n");
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
free(ml);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
free(n->mlnode_data);
|
||||
}
|
||||
free(n);
|
||||
}
|
||||
|
||||
void* mlist_node_get_data(mlist_node_t* node)
|
||||
{
|
||||
CHK_MLIST_NODE(node);
|
||||
return node->mlnode_data;
|
||||
}
|
||||
|
||||
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 *) 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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);
|
||||
}
|
||||
|
||||
void* mlist_cursor_get_data_nomutex(mlist_cursor_t* mc)
|
||||
{
|
||||
CHK_MLIST_CURSOR(mc);
|
||||
return (mc->mlcursor_pos->mlnode_data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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*) calloc(1, sizeof (mlist_node_t));
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif /* MLIST */
|
||||
|
||||
/** End of mlist */
|
||||
|
||||
|
||||
size_t get_timestamp_len(void)
|
||||
{
|
||||
return timestamp_len;
|
||||
|
@ -8,7 +8,6 @@
|
||||
#define STRERROR_BUFLEN 512
|
||||
#endif
|
||||
|
||||
#define MLIST
|
||||
#ifndef MIN
|
||||
#define MIN(a,b) (a<b ? a : b)
|
||||
#endif
|
||||
@ -22,7 +21,6 @@
|
||||
|
||||
#define DISKWRITE_LATENCY (5*MSEC_USEC)
|
||||
|
||||
typedef struct mlist_node_st mlist_node_t;
|
||||
typedef struct skygw_file_st skygw_file_t;
|
||||
typedef struct skygw_thread_st skygw_thread_t;
|
||||
typedef struct skygw_message_st skygw_message_t;
|
||||
@ -46,41 +44,6 @@ typedef struct skygw_rwlock_st {
|
||||
} skygw_rwlock_t;
|
||||
|
||||
|
||||
typedef struct mlist_st {
|
||||
skygw_chk_t mlist_chk_top;
|
||||
char* mlist_name;
|
||||
void (*mlist_datadel)(void *); /**< clean-up function for data */
|
||||
simple_mutex_t mlist_mutex; /**< protect node updates and clean-up */
|
||||
bool mlist_uselock;
|
||||
bool mlist_islocked;
|
||||
bool mlist_deleted;
|
||||
size_t mlist_nodecount;
|
||||
size_t mlist_nodecount_max; /**< size limit. 0 == no limit */
|
||||
size_t mlist_versno;
|
||||
bool mlist_flat;
|
||||
mlist_node_t* mlist_first;
|
||||
mlist_node_t* mlist_last;
|
||||
skygw_chk_t mlist_chk_tail;
|
||||
} mlist_t;
|
||||
|
||||
typedef struct mlist_cursor_st {
|
||||
skygw_chk_t mlcursor_chk_top;
|
||||
mlist_t* mlcursor_list;
|
||||
mlist_node_t* mlcursor_pos;
|
||||
pthread_t* mlcursor_owner_thr;
|
||||
skygw_chk_t mlcursor_chk_tail;
|
||||
} mlist_cursor_t;
|
||||
|
||||
struct mlist_node_st {
|
||||
skygw_chk_t mlnode_chk_top;
|
||||
mlist_t* mlnode_list;
|
||||
mlist_node_t* mlnode_next;
|
||||
void* mlnode_data;
|
||||
bool mlnode_deleted;
|
||||
skygw_chk_t mlnode_chk_tail;
|
||||
};
|
||||
|
||||
|
||||
typedef enum { THR_INIT, THR_RUNNING, THR_STOPPED, THR_DONE } skygw_thr_state_t;
|
||||
typedef enum { MES_RC_FAIL, MES_RC_SUCCESS, MES_RC_TIMEOUT } skygw_mes_rc_t;
|
||||
|
||||
@ -133,27 +96,6 @@ void utils_end();
|
||||
|
||||
EXTERN_C_BLOCK_END
|
||||
|
||||
mlist_t* mlist_init(mlist_t* mlist,
|
||||
mlist_cursor_t** cursor,
|
||||
char* name,
|
||||
void (*datadel)(void*),
|
||||
int maxnodes);
|
||||
|
||||
void mlist_done(mlist_t* list);
|
||||
bool mlist_add_data_nomutex(mlist_t* list, void* data);
|
||||
bool mlist_add_node_nomutex(mlist_t* list, mlist_node_t* newnode);
|
||||
void* mlist_node_get_data(mlist_node_t* node);
|
||||
mlist_node_t* mlist_detach_nodes(mlist_t* ml);
|
||||
mlist_node_t* mlist_detach_first(mlist_t* ml);
|
||||
void mlist_node_done(mlist_node_t* n);
|
||||
|
||||
int mlist_cursor_done(mlist_cursor_t* c);
|
||||
mlist_cursor_t* mlist_cursor_init(mlist_t* ml);
|
||||
void mlist_cursor_add_data(mlist_cursor_t* c, void* data);
|
||||
void* mlist_cursor_get_data_nomutex(mlist_cursor_t* c);
|
||||
bool mlist_cursor_move_to_first(mlist_cursor_t* c);
|
||||
bool mlist_cursor_step_ahead(mlist_cursor_t* c);
|
||||
|
||||
/** Skygw thread routines */
|
||||
skygw_thread_t* skygw_thread_init(
|
||||
const char* name,
|
||||
|
Reference in New Issue
Block a user