src/lib/doubly_linked_list.c
/*
* Author: Yasuhito Takamiya <yasuhito@gmail.com>
*
* Copyright (C) 2008-2013 NEC Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2, as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <assert.h>
#include <pthread.h>
#include "doubly_linked_list.h"
#include "wrapper.h"
typedef struct private_dlist_element {
dlist_element public;
pthread_mutex_t *mutex;
} private_dlist_element;
static dlist_element *
create_dlist_with_mutex( pthread_mutex_t *mutex ) {
private_dlist_element *element = xmalloc( sizeof( private_dlist_element ) );
element->public.data = NULL;
element->public.prev = NULL;
element->public.next = NULL;
element->mutex = mutex;
return ( dlist_element * ) element;
}
/**
* Allocates space for one dlist_element.
*
* @return a pointer to the newly-allocated dlist_element.
*/
dlist_element *
create_dlist() {
private_dlist_element *element = ( private_dlist_element * ) create_dlist_with_mutex( NULL );
pthread_mutexattr_t attr;
pthread_mutexattr_init( &attr );
pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_RECURSIVE_NP );
element->mutex = xmalloc( sizeof( pthread_mutex_t ) );
pthread_mutex_init( element->mutex, &attr );
return ( dlist_element * ) element;
}
/**
* Inserts a new element into the list before the given position.
*
* @param element the list element before which the new element is inserted.
* @param data the data for the new element.
* @return a pointer to newly inserted element.
*/
dlist_element *
insert_before_dlist( dlist_element *element, void *data ) {
if ( element == NULL ) {
die( "element must not be NULL" );
}
pthread_mutex_lock( ( ( private_dlist_element * ) element )->mutex );
pthread_mutex_t *mutex = ( ( private_dlist_element * ) element )->mutex;
dlist_element *new_prev = create_dlist_with_mutex( mutex );
if ( element->prev ) {
dlist_element *old_prev = element->prev;
new_prev->prev = old_prev;
old_prev->next = new_prev;
}
element->prev = new_prev;
new_prev->next = element;
new_prev->data = data;
pthread_mutex_unlock( mutex );
return new_prev;
}
/**
* Inserts a new element into the list after the given position.
*
* @param element the list element after which the new element is inserted.
* @param data the data for the new element.
* @return a pointer to newly inserted element.
*/
dlist_element *
insert_after_dlist( dlist_element *element, void *data ) {
if ( element == NULL ) {
die( "element must not be NULL" );
}
pthread_mutex_lock( ( ( private_dlist_element * ) element )->mutex );
pthread_mutex_t *mutex = ( ( private_dlist_element * ) element )->mutex;
dlist_element *new_next = create_dlist_with_mutex( mutex );
if ( element->next ) {
dlist_element *old_next = element->next;
new_next->next = old_next;
old_next->prev = new_next;
}
element->next = new_next;
new_next->prev = element;
new_next->data = data;
pthread_mutex_unlock( mutex );
return new_next;
}
/**
* Gets the first element in a list.
*
* @param element a pointer to any of the element in the list.
* @return the first element in the list.
*/
dlist_element *
get_first_element( dlist_element *element ) {
if ( element == NULL ) {
die( "element must not be NULL" );
}
pthread_mutex_lock( ( ( private_dlist_element * ) element )->mutex );
while ( element->prev != NULL ) {
element = element->prev;
}
pthread_mutex_unlock( ( ( private_dlist_element * ) element )->mutex );
return element;
}
/**
* Gets the last element in a list.
*
* @param element a pointer to any of the element in the list.
* @return the last element in the list.
*/
dlist_element *
get_last_element( dlist_element *element ) {
if ( element == NULL ) {
die( "element must not be NULL" );
}
pthread_mutex_lock( ( ( private_dlist_element * ) element )->mutex );
while ( element->next != NULL ) {
element = element->next;
}
pthread_mutex_unlock( ( ( private_dlist_element * ) element )->mutex );
return element;
}
/**
* Finds the element in a list which contains the given data.
*
* @param element a pointer to any of the element in the list.
* @param data the element data to find.
* @return the found list element, or NULL if it is not found.
*/
dlist_element *
find_element( dlist_element *element, const void *data ) {
if ( element == NULL ) {
die( "element must not be NULL" );
}
pthread_mutex_lock( ( ( private_dlist_element * ) element )->mutex );
dlist_element *e = NULL;
for ( e = element; e; e = e->next ) {
if ( e->data == data ) {
pthread_mutex_unlock( ( ( private_dlist_element * ) element )->mutex );
return e;
}
}
for ( e = element->prev; e; e = e->prev ) {
if ( e->data == data ) {
pthread_mutex_unlock( ( ( private_dlist_element * ) element )->mutex );
return e;
}
}
pthread_mutex_unlock( ( ( private_dlist_element * ) element )->mutex );
return NULL;
}
/**
* Removes an element from a list. If two elements contain the same
* data, only the first is removed. If none of the elements contain
* the data, the list is unchanged.
*
* @param element a element to remove.
* @return true on success; false otherwise.
*/
bool
delete_dlist_element( dlist_element *element ) {
if ( element == NULL ) {
die( "element must not be NULL" );
}
pthread_mutex_lock( ( ( private_dlist_element * ) element )->mutex );
pthread_mutex_t *mutex = ( ( private_dlist_element * ) element )->mutex;
if ( element->prev != NULL ) {
element->prev->next = element->next;
}
if ( element->next != NULL ) {
element->next->prev = element->prev;
}
xfree( ( private_dlist_element * ) element );
pthread_mutex_unlock( mutex );
return true;
}
/**
* Removes all elements from a list.
*
* @param element a pointer to any of the element in the list.
* @return true on success; false otherwise.
*/
bool
delete_dlist( dlist_element *element ) {
if ( element == NULL ) {
die( "element must not be NULL" );
}
pthread_mutex_lock( ( ( private_dlist_element * ) element )->mutex );
pthread_mutex_t *mutex = ( ( private_dlist_element * ) element )->mutex;
dlist_element *e = NULL;
while ( element->prev != NULL ) {
element = element->prev;
}
for ( e = element; e != NULL; ) {
dlist_element *delete_me = e;
e = e->next;
xfree( ( private_dlist_element * ) delete_me );
}
pthread_mutex_unlock( mutex );
xfree( mutex );
return true;
}
/*
* Local variables:
* c-basic-offset: 2
* indent-tabs-mode: nil
* End:
*/