第四章 并发与同步

4.1 并发

4.2 同步

/*
 * File:    typedef.h
 */

#include <stdio.h>

#ifndef TYPEDEF_H
#define TYPEDEF_H

typedef enum _Ret
{
	RET_OK,
	RET_OOM,
	RET_STOP,
	RET_INVALID_PARAMS,
	RET_FAIL
}Ret;

#ifdef __cplusplus
#define DECLS_BEGIN extern "C" {
#define DECLS_END   }
#else
#define DECLS_BEGIN
#define DECLS_END
#endif/*__cplusplus*/

#define return_if_fail(p) if(!(p)) \
	{printf("%s:%d Warning: "#p" failed.\n", \
		__func__, __LINE__); return;}
#define return_val_if_fail(p, ret) if(!(p)) \
	{printf("%s:%d Warning: "#p" failed.\n",\
	__func__, __LINE__); return (ret);}

#define SAFE_FREE(p) if(p != NULL) {free(p); p = NULL;}

#endif/*TYPEDEF_H*/

/*
 * File:    locker
 */

#include "typedef.h"

#ifndef LOCKER_H
#define LOCKER_H

DECLS_BEGIN

struct _Locker;
typedef struct _Locker Locker;

typedef Ret  (*LockerLockFunc)(Locker* thiz);
typedef Ret  (*LockerUnlockFunc)(Locker* thiz);
typedef void (*LockerDestroyFunc)(Locker* thiz);

struct _Locker
{
	LockerLockFunc    lock;
	LockerUnlockFunc  unlock;
	LockerDestroyFunc destroy;

	char priv[0];
};

static inline Ret locker_lock(Locker* thiz)
{
	return_val_if_fail(thiz != NULL && thiz->lock != NULL, RET_INVALID_PARAMS);

	return thiz->lock(thiz);
}

static inline Ret locker_unlock(Locker* thiz)
{
	return_val_if_fail(thiz != NULL && thiz->unlock != NULL, RET_INVALID_PARAMS);

	return thiz->unlock(thiz);
}

static inline void locker_destroy(Locker* thiz)
{
	return_if_fail(thiz != NULL && thiz->destroy != NULL);

	thiz->destroy(thiz);

	return;
}

DECLS_END

#endif/*LOCKER_H*/

/*
 * File:    locker_pthread.h
 */
#include "locker.h"

#ifndef LOCKER_PTHREAD_H
#define LOCKER_PTHREAD_H

DECLS_BEGIN

Locker* locker_pthread_create(void);

DECLS_END

#endif/*LOCKER_PTHREAD_H*/

/*
 * File:    locker_pthread.c
 */

#include <stdlib.h>
#include <pthread.h>
#include "locker_pthread.h"

typedef struct _PrivInfo
{
	pthread_mutex_t mutex;
}PrivInfo;

static Ret  locker_pthread_lock(Locker* thiz)
{
	PrivInfo* priv = (PrivInfo*)thiz->priv;

	int ret = pthread_mutex_lock(&priv->mutex);

	return ret == 0 ? RET_OK : RET_FAIL;
}

static Ret  locker_pthread_unlock(Locker* thiz)
{
	PrivInfo* priv = (PrivInfo*)thiz->priv;

	int ret = pthread_mutex_unlock(&priv->mutex);

	return ret == 0 ? RET_OK : RET_FAIL;
}

static void locker_pthread_destroy(Locker* thiz)
{
	PrivInfo* priv = (PrivInfo*)thiz->priv;

	int ret = pthread_mutex_destroy(&priv->mutex);

	SAFE_FREE(thiz);

	return;
}

Locker* locker_pthread_create(void)
{
	Locker* thiz = (Locker*)malloc(sizeof(Locker) + sizeof(PrivInfo));

	if(thiz != NULL)
	{
		PrivInfo* priv = (PrivInfo*)thiz->priv;

		thiz->lock    = locker_pthread_lock;
		thiz->unlock  = locker_pthread_unlock;
		thiz->destroy = locker_pthread_destroy;

		pthread_mutex_init(&(priv->mutex), NULL);
	}

	return thiz;
}


/*
 * File:    dlist.h
 */

#include <stdio.h>
#include "locker.h"

#ifndef DLIST_H
#define DLIST_H

DECLS_BEGIN

struct _DList;
typedef struct _DList DList;

typedef void     (*DListDataDestroyFunc)(void* ctx, void* data);
typedef int      (*DListDataCompareFunc)(void* ctx, void* data);
typedef Ret      (*DListDataVisitFunc)(void* ctx, void* data);

DList* dlist_create(DListDataDestroyFunc data_destroy, void* ctx, Locker* locker);

Ret dlist_insert(DList* thiz, size_t index, void* data);
Ret dlist_prepend(DList* thiz, void* data);
Ret dlist_append(DList* thiz, void* data);
Ret dlist_delete(DList* thiz, size_t index);
Ret dlist_get_by_index(DList* thiz, size_t index, void** data);
Ret dlist_set_by_index(DList* thiz, size_t index, void* data);
size_t   dlist_length(DList* thiz);
int      dlist_find(DList* thiz, DListDataCompareFunc cmp, void* ctx);
Ret      dlist_foreach(DList* thiz, DListDataVisitFunc visit, void* ctx);

void dlist_destroy(DList* thiz);

DECLS_END

#endif/*DLIST*/

/*
 * File:    dlist.c
 */

#include <stdlib.h>
#include <unistd.h>
#include "dlist.h"

typedef struct _DListNode
{
	struct _DListNode* prev;
	struct _DListNode* next;

	void* data;
}DListNode;

struct _DList
{
	Locker* locker;
	DListNode* first;
	void* data_destroy_ctx;
	DListDataDestroyFunc data_destroy;
};

static void dlist_destroy_data(DList* thiz, void* data)
{
	if(thiz->data_destroy != NULL)
	{
		thiz->data_destroy(thiz->data_destroy_ctx, data);
	}

	return;
}

static DListNode* dlist_create_node(DList* thiz, void* data)
{
	DListNode* node = malloc(sizeof(DListNode));

	if(node != NULL)
	{
		node->prev = NULL;
		node->next = NULL;
		node->data = data;
	}

	return node;
}

static void dlist_destroy_node(DList* thiz, DListNode* node)
{
	if(node != NULL)
	{
		node->next = NULL;
		node->prev = NULL;
		dlist_destroy_data(thiz, node->data);
		SAFE_FREE(node);
	}

	return;
}

static void dlist_lock(DList* thiz)
{
	if(thiz->locker != NULL)
	{
		locker_lock(thiz->locker);
	}

	return;
}

static void dlist_unlock(DList* thiz)
{
	if(thiz->locker != NULL)
	{
		locker_unlock(thiz->locker);
	}

	return;
}

static void dlist_destroy_locker(DList* thiz)
{
	if(thiz->locker != NULL)
	{
		locker_unlock(thiz->locker);
		locker_destroy(thiz->locker);
	}

	return;
}

DList* dlist_create(DListDataDestroyFunc data_destroy, void* ctx, Locker* locker)
{
	DList* thiz = malloc(sizeof(DList));

	if(thiz != NULL)
	{
		thiz->first  = NULL;
		thiz->locker = locker;
		thiz->data_destroy = data_destroy;
		thiz->data_destroy_ctx = ctx;
	}

	return thiz;
}

static DListNode* dlist_get_node(DList* thiz, size_t index, int fail_return_last)
{
	DListNode* iter = NULL;
	
	return_val_if_fail(thiz != NULL, NULL); 

	iter = thiz->first;

	while(iter != NULL && iter->next != NULL && index > 0)
	{
		iter = iter->next;
		index--;
	}

	if(!fail_return_last)
	{
		iter = index > 0 ? NULL : iter;
	}

	return iter;
}

Ret dlist_insert(DList* thiz, size_t index, void* data)
{
	Ret ret = RET_OK;
	DListNode* node = NULL;
	DListNode* cursor = NULL;

	return_val_if_fail(thiz != NULL, RET_INVALID_PARAMS); 

	dlist_lock(thiz);

	do
	{
		if((node = dlist_create_node(thiz, data)) == NULL)
		{
			ret = RET_OOM;
			break;
		}

		if(thiz->first == NULL)
		{
			thiz->first = node;
			break;
		}

		cursor = dlist_get_node(thiz, index, 1);
		
		if(index < dlist_length(thiz))
		{
			node->next = cursor;
			if(cursor->prev != NULL)
			{
				cursor->prev->next = node;
			}
			cursor->prev = node;
			if(thiz->first == cursor)
			{
				thiz->first = node;
			}
		}
		else
		{
			cursor->next = node;
			node->prev = cursor;
		}
	}while(0);

	dlist_unlock(thiz);

	return ret;
}

Ret dlist_prepend(DList* thiz, void* data)
{
	return dlist_insert(thiz, 0, data);
}

Ret dlist_append(DList* thiz, void* data)
{
	return dlist_insert(thiz, -1, data);
}

Ret dlist_delete(DList* thiz, size_t index)
{
	Ret ret = RET_OK;
	DListNode* cursor = NULL;

	return_val_if_fail(thiz != NULL, RET_INVALID_PARAMS); 
	
	dlist_lock(thiz);
	cursor = dlist_get_node(thiz, index, 0);

	do
	{
		if(cursor == NULL)
		{
			ret = RET_INVALID_PARAMS;
			break;
		}

		if(cursor != NULL)
		{
			if(cursor == thiz->first)
			{
				thiz->first = cursor->next;
			}

			if(cursor->next != NULL)
			{
				cursor->next->prev = cursor->prev;
			}

			if(cursor->prev != NULL)
			{
				cursor->prev->next = cursor->next;
			}

			dlist_destroy_node(thiz, cursor);
		}

	}while(0);

	dlist_unlock(thiz);

	return RET_OK;
}

Ret dlist_get_by_index(DList* thiz, size_t index, void** data)
{
	DListNode* cursor = NULL;

	return_val_if_fail(thiz != NULL && data != NULL, RET_INVALID_PARAMS); 

	dlist_lock(thiz);

	cursor = dlist_get_node(thiz, index, 0);

	if(cursor != NULL)
	{
		*data = cursor->data;
	}
	dlist_unlock(thiz);

	return cursor != NULL ? RET_OK : RET_INVALID_PARAMS;
}

Ret dlist_set_by_index(DList* thiz, size_t index, void* data)
{
	DListNode* cursor = NULL;

	return_val_if_fail(thiz != NULL, RET_INVALID_PARAMS);

	dlist_lock(thiz);
	
	cursor = dlist_get_node(thiz, index, 0);

	if(cursor != NULL)
	{
		cursor->data = data;
	}

	dlist_unlock(thiz);

	return cursor != NULL ? RET_OK : RET_INVALID_PARAMS;
}

size_t   dlist_length(DList* thiz)
{
	size_t length = 0;
	DListNode* iter = NULL;
	
	return_val_if_fail(thiz != NULL, 0);

	dlist_lock(thiz);

	iter = thiz->first;

	while(iter != NULL)
	{
		length++;
		iter = iter->next;
	}

	dlist_unlock(thiz);

	return length;
}

Ret dlist_foreach(DList* thiz, DListDataVisitFunc visit, void* ctx)
{
	Ret ret = RET_OK;
	DListNode* iter = NULL;
	
	return_val_if_fail(thiz != NULL && visit != NULL, RET_INVALID_PARAMS);

	dlist_lock(thiz);

	iter = thiz->first;

	while(iter != NULL && ret != RET_STOP)
	{
		ret = visit(ctx, iter->data);

		iter = iter->next;
	}
	dlist_unlock(thiz);

	return ret;
}

int      dlist_find(DList* thiz, DListDataCompareFunc cmp, void* ctx)
{
	int i = 0;
	DListNode* iter = NULL;

	return_val_if_fail(thiz != NULL && cmp != NULL, -1);

	dlist_lock(thiz);

	iter = thiz->first;
	while(iter != NULL)
	{
		if(cmp(ctx, iter->data) == 0)
		{
			break;
		}
		i++;
		iter = iter->next;
	}

	dlist_unlock(thiz);

	return i;
}

void dlist_destroy(DList* thiz)
{
	DListNode* iter = NULL;
	DListNode* next = NULL;
	
	return_if_fail(thiz != NULL);

	dlist_lock(thiz);

	iter = thiz->first;
	while(iter != NULL)
	{
		next = iter->next;
		dlist_destroy_node(thiz, iter);
		iter = next;
	}

	thiz->first = NULL;
	dlist_destroy_locker(thiz);
	
	SAFE_FREE(thiz);

	return;
}

#ifdef DLIST_TEST

#include <assert.h>
#include <pthread.h>
#include "locker_pthread.h"

static int cmp_int(void* ctx, void* data)
{
	return (int)data - (int)ctx;
}

static Ret print_int(void* ctx, void* data)
{
	printf("%d ", (int)data);

	return RET_OK;
}

static Ret check_and_dec_int(void* ctx, void* data)
{
	int* expected =(int*)ctx;
	assert(*expected == (int)data);

	(*expected)--;

	return RET_OK;
}

static void test_int_dlist(void)
{
	int i = 0;
	int n = 100;
	int data = 0;
	DList* dlist = dlist_create(NULL, NULL, NULL);

	for(i = 0; i < n; i++)
	{
		assert(dlist_append(dlist, (void*)i) == RET_OK);
		assert(dlist_length(dlist) == (i + 1));
		assert(dlist_get_by_index(dlist, i, (void**)&data) == RET_OK);
		assert(data == i);
		assert(dlist_set_by_index(dlist, i, (void*)(2*i)) == RET_OK);
		assert(dlist_get_by_index(dlist, i, (void**)&data) == RET_OK);
		assert(data == 2*i);
		assert(dlist_set_by_index(dlist, i, (void*)i) == RET_OK);
		assert(dlist_find(dlist, cmp_int, (void*)i) == i);
	}

	for(i = 0; i < n; i++)
	{
		assert(dlist_get_by_index(dlist, 0, (void**)&data) == RET_OK);
		assert(data == (i));
		assert(dlist_length(dlist) == (n-i));
		assert(dlist_delete(dlist, 0) == RET_OK);
		assert(dlist_length(dlist) == (n-i-1));
		if((i + 1) < n)
		{
			assert(dlist_get_by_index(dlist, 0, (void**)&data) == RET_OK);
			assert((int)data == (i+1));
		}
	}
	
	assert(dlist_length(dlist) == 0);

	for(i = 0; i < n; i++)
	{
		assert(dlist_prepend(dlist, (void*)i) == RET_OK);
		assert(dlist_length(dlist) == (i + 1));
		assert(dlist_get_by_index(dlist, 0, (void**)&data) == RET_OK);
		assert(data == i);
		assert(dlist_set_by_index(dlist, 0, (void*)(2*i)) == RET_OK);
		assert(dlist_get_by_index(dlist, 0, (void**)&data) == RET_OK);
		assert(data == 2*i);
		assert(dlist_set_by_index(dlist, 0, (void*)i) == RET_OK);
	}

	i = n - 1;
	assert(dlist_foreach(dlist, check_and_dec_int, &i) == RET_OK);

	dlist_destroy(dlist);

	return;
}

static void test_invalid_params(void)
{
	printf("===========Warning is normal begin==============\n");
	assert(dlist_length(NULL) == 0);
	assert(dlist_prepend(NULL, 0) == RET_INVALID_PARAMS);
	assert(dlist_append(NULL, 0) == RET_INVALID_PARAMS);
	assert(dlist_delete(NULL, 0) == RET_INVALID_PARAMS);
	assert(dlist_insert(NULL, 0, 0) == RET_INVALID_PARAMS);
	assert(dlist_set_by_index(NULL, 0, 0) == RET_INVALID_PARAMS);
	assert(dlist_get_by_index(NULL, 0, NULL) == RET_INVALID_PARAMS);
	assert(dlist_find(NULL, NULL, NULL) < 0);
	assert(dlist_foreach(NULL, NULL, NULL) == RET_INVALID_PARAMS);
	printf("===========Warning is normal end==============\n");

	return;
}

static void single_thread_test(void)
{
	test_int_dlist();
	test_invalid_params();

	return;
}

static void* producer(void* param)
{
	int i = 0;
	DList* dlist = (DList*)param;

	for(i = 0; i < 100; i++)
	{
		assert(dlist_append(dlist, (void*)i) == RET_OK);
	}
	sleep(1);
	for(i = 0; i < 100; i++)
	{
		assert(dlist_prepend(dlist, (void*)i) == RET_OK);
	}

	return NULL;
}

static void* consumer(void* param)
{
	int i = 0;
	DList* dlist = (DList*)param;

	for(i = 0; i < 200; i++)
	{
		usleep(20);
		assert(dlist_delete(dlist, 0) == RET_OK);
	}

	return NULL;
}

static void multi_thread_test(void)
{
	pthread_t consumer_tid = 0;
	pthread_t producer_tid = 0;
	DList* dlist = dlist_create(NULL, NULL, locker_pthread_create());
	pthread_create(&producer_tid, NULL, producer, dlist);
	pthread_create(&consumer_tid, NULL, consumer, dlist);

	pthread_join(consumer_tid, NULL);
	pthread_join(producer_tid, NULL);

	return;
}
int main(int argc, char* argv[])
{
	single_thread_test();
	multi_thread_test();

	return 0;
}
#endif

CFILES=dlist.c  locker_pthread.c 
all:
	#gcc -g -m32 -fPIC -shared -lpthread $(CFILES)  -o libdlist.so  
	gcc -g -m32 -shared -lpthread $(CFILES)  -o libdlist.so  
	gcc -g -m32 -DDLIST_TEST  $(CFILES)  -o dlist_test  -lpthread

clean:
	rm -f *test *.exe *.so

4.3 嵌套锁与装饰模式

/*
 * File:    typedef.h
 */

#include <stdio.h>
#include <assert.h>
#include <stdlib.h>

#ifndef TYPEDEF_H
#define TYPEDEF_H

typedef enum _Ret
{
	RET_OK,
	RET_OOM,
	RET_STOP,
	RET_INVALID_PARAMS,
	RET_FAIL
}Ret;

#ifdef __cplusplus
#define DECLS_BEGIN extern "C" {
#define DECLS_END   }
#else
#define DECLS_BEGIN
#define DECLS_END
#endif/*__cplusplus*/

#define return_if_fail(p) if(!(p)) \
	{printf("%s:%d Warning: "#p" failed.\n", \
		__func__, __LINE__); return;}
#define return_val_if_fail(p, ret) if(!(p)) \
	{printf("%s:%d Warning: "#p" failed.\n",\
	__func__, __LINE__); return (ret);}

#define SAFE_FREE(p) if(p != NULL) {free(p); p = NULL;}

#endif/*TYPEDEF_H*/

/*
 * File:    locker.h
 */

#include "typedef.h"

#ifndef LOCKER_H
#define LOCKER_H

DECLS_BEGIN

struct _Locker;
typedef struct _Locker Locker;

typedef Ret  (*LockerLockFunc)(Locker* thiz);
typedef Ret  (*LockerUnlockFunc)(Locker* thiz);
typedef void (*LockerDestroyFunc)(Locker* thiz);

struct _Locker
{
	LockerLockFunc    lock;
	LockerUnlockFunc  unlock;
	LockerDestroyFunc destroy;

	char priv[0];
};

static inline Ret locker_lock(Locker* thiz)
{
	return_val_if_fail(thiz != NULL && thiz->lock != NULL, RET_INVALID_PARAMS);

	return thiz->lock(thiz);
}

static inline Ret locker_unlock(Locker* thiz)
{
	return_val_if_fail(thiz != NULL && thiz->unlock != NULL, RET_INVALID_PARAMS);

	return thiz->unlock(thiz);
}

static inline void locker_destroy(Locker* thiz)
{
	return_if_fail(thiz != NULL && thiz->destroy != NULL);

	thiz->destroy(thiz);

	return;
}

DECLS_END

#endif/*LOCKER_H*/

/*
 * File:    locker_pthread.h
 */

#include "locker.h"

#ifndef LOCKER_PTHREAD_H
#define LOCKER_PTHREAD_H

DECLS_BEGIN

Locker* locker_pthread_create(void);

DECLS_END

#endif/*LOCKER_PTHREAD_H*/

/*
 * File:    locker_pthread.c
 */

#include <stdlib.h>
#include <pthread.h>
#include "locker_pthread.h"

typedef struct _PrivInfo
{
	pthread_mutex_t mutex;
}PrivInfo;

static Ret  locker_pthread_lock(Locker* thiz)
{
	PrivInfo* priv = (PrivInfo*)thiz->priv;

	int ret = pthread_mutex_lock(&priv->mutex);

	return ret == 0 ? RET_OK : RET_FAIL;
}

static Ret  locker_pthread_unlock(Locker* thiz)
{
	PrivInfo* priv = (PrivInfo*)thiz->priv;

	int ret = pthread_mutex_unlock(&priv->mutex);

	return ret == 0 ? RET_OK : RET_FAIL;
}

static void locker_pthread_destroy(Locker* thiz)
{
	PrivInfo* priv = (PrivInfo*)thiz->priv;

	int ret = pthread_mutex_destroy(&priv->mutex);

	SAFE_FREE(thiz);

	return;
}

Locker* locker_pthread_create(void)
{
	Locker* thiz = (Locker*)malloc(sizeof(Locker) + sizeof(PrivInfo));

	if(thiz != NULL) {
		PrivInfo* priv = (PrivInfo*)thiz->priv;

		thiz->lock    = locker_pthread_lock;
		thiz->unlock  = locker_pthread_unlock;
		thiz->destroy = locker_pthread_destroy;

		pthread_mutex_init(&(priv->mutex), NULL);
	}

	return thiz;
}


/*
 * File:    locker_nest.h
 */

#include "locker.h"

#ifndef LOCKER_NEST_H
#define LOCKER_NEST_H

DECLS_BEGIN

typedef int (*TaskSelfFunc)(void);
Locker* locker_nest_create(Locker* real_locker, TaskSelfFunc task_self);

DECLS_END

#endif/*LOCKER_NEST_H*/

/*
 * File:    locker_nest.c
 */

#include "locker_nest.h"

typedef struct _PrivInfo
{
	int owner;
	int refcount;
	Locker* real_locker;
	TaskSelfFunc task_self;
}PrivInfo;

static Ret  locker_nest_lock(Locker* thiz)
{
	Ret ret = RET_OK;
	PrivInfo* priv = (PrivInfo*)thiz->priv;

	if(priv->owner == priv->task_self()) {
		priv->refcount++;
	} else {
		if( (ret = locker_lock(priv->real_locker)) == RET_OK) {
			priv->refcount = 1;
			priv->owner = priv->task_self();
		}
	}

	return ret;
}

static Ret  locker_nest_unlock(Locker* thiz)
{
	Ret ret = RET_OK;
	PrivInfo* priv = (PrivInfo*)thiz->priv;

	return_val_if_fail(priv->owner == priv->task_self(), RET_FAIL);
	
	priv->refcount--;
	if(priv->refcount == 0) {
		priv->owner = 0;
		ret = locker_unlock(priv->real_locker);
	}

	return ret;
}

static void  locker_nest_destroy(Locker* thiz)
{
	PrivInfo* priv = (PrivInfo*)thiz->priv;

	priv->owner = 0;
	priv->refcount = 0;
	locker_destroy(priv->real_locker);
	priv->real_locker = NULL;

	SAFE_FREE(thiz);

	return;
}

Locker* locker_nest_create(Locker* real_locker, TaskSelfFunc task_self)
{
	Locker* thiz = NULL;
	return_val_if_fail(real_locker != NULL && task_self != NULL, NULL);
	
	thiz = (Locker*)malloc(sizeof(Locker) + sizeof(PrivInfo));

	if(thiz != NULL) {
		PrivInfo* priv = (PrivInfo*)thiz->priv;

		thiz->lock    = locker_nest_lock;
		thiz->unlock  = locker_nest_unlock;
		thiz->destroy = locker_nest_destroy;

		priv->owner = 0;
		priv->refcount = 0;
		priv->real_locker = real_locker;
		priv->task_self = task_self;
	}

	return thiz;
}

/*
 * File:    dlist.h
 */

#include <stdio.h>
#include "locker.h"

#ifndef DLIST_H
#define DLIST_H

DECLS_BEGIN

struct _DList;
typedef struct _DList DList;

typedef void     (*DListDataDestroyFunc)(void* ctx, void* data);
typedef int      (*DListDataCompareFunc)(void* ctx, void* data);
typedef Ret      (*DListDataVisitFunc)(void* ctx, void* data);

DList* dlist_create(DListDataDestroyFunc data_destroy, void* ctx, Locker* locker);

Ret dlist_insert(DList* thiz, size_t index, void* data);
Ret dlist_prepend(DList* thiz, void* data);
Ret dlist_append(DList* thiz, void* data);
Ret dlist_delete(DList* thiz, size_t index);
Ret dlist_get_by_index(DList* thiz, size_t index, void** data);
Ret dlist_set_by_index(DList* thiz, size_t index, void* data);
size_t   dlist_length(DList* thiz);
int      dlist_find(DList* thiz, DListDataCompareFunc cmp, void* ctx);
Ret      dlist_foreach(DList* thiz, DListDataVisitFunc visit, void* ctx);

void dlist_destroy(DList* thiz);

DECLS_END

#endif/*DLIST*/

/*
 * File:    dlist.c
 */

#include <stdlib.h>
#include <unistd.h>
#include "dlist.h"

typedef struct _DListNode
{
	struct _DListNode* prev;
	struct _DListNode* next;

	void* data;
}DListNode;

struct _DList
{
	Locker* locker;
	DListNode* first;
	void* data_destroy_ctx;
	DListDataDestroyFunc data_destroy;
};

static void dlist_destroy_data(DList* thiz, void* data)
{
	if(thiz->data_destroy != NULL){
		thiz->data_destroy(thiz->data_destroy_ctx, data);
	}

	return;
}

static DListNode* dlist_create_node(DList* thiz, void* data)
{
	DListNode* node = malloc(sizeof(DListNode));

	if(node != NULL){
		node->prev = NULL;
		node->next = NULL;
		node->data = data;
	}

	return node;
}

static void dlist_destroy_node(DList* thiz, DListNode* node)
{
	if(node != NULL){
		node->next = NULL;
		node->prev = NULL;
		dlist_destroy_data(thiz, node->data);
		SAFE_FREE(node);
	}

	return;
}

static void dlist_lock(DList* thiz)
{
	if(thiz->locker != NULL){
		locker_lock(thiz->locker);
	}

	return;
}

static void dlist_unlock(DList* thiz)
{
	if(thiz->locker != NULL) {
		locker_unlock(thiz->locker);
	}

	return;
}

static void dlist_destroy_locker(DList* thiz)
{
	if(thiz->locker != NULL) {
		locker_unlock(thiz->locker);
		locker_destroy(thiz->locker);
		thiz->locker = NULL;
	}

	return;
}

DList* dlist_create(DListDataDestroyFunc data_destroy, void* ctx, Locker* locker)
{
	DList* thiz = malloc(sizeof(DList));

	if(thiz != NULL){
		thiz->first  = NULL;
		thiz->locker = locker;
		thiz->data_destroy = data_destroy;
		thiz->data_destroy_ctx = ctx;
	}

	return thiz;
}

static DListNode* dlist_get_node(DList* thiz, size_t index, int fail_return_last)
{
	DListNode* iter = NULL;
	
	return_val_if_fail(thiz != NULL, NULL); 

	iter = thiz->first;

	while(iter != NULL && iter->next != NULL && index > 0) {
		iter = iter->next;
		index--;
	}

	if(!fail_return_last) {
		iter = index > 0 ? NULL : iter;
	}

	return iter;
}

Ret dlist_insert(DList* thiz, size_t index, void* data)
{
	Ret ret = RET_OK;
	DListNode* node = NULL;
	DListNode* cursor = NULL;

	return_val_if_fail(thiz != NULL, RET_INVALID_PARAMS); 

	dlist_lock(thiz);

	do
	{
		if((node = dlist_create_node(thiz, data)) == NULL) {
			ret = RET_OOM;
			break;
		}

		if(thiz->first == NULL) {
			thiz->first = node;
			break;
		}

		cursor = dlist_get_node(thiz, index, 1);
		
		if(index < dlist_length(thiz)) {
			node->next = cursor;
			if(cursor->prev != NULL) {
				cursor->prev->next = node;
			}
			cursor->prev = node;
			if(thiz->first == cursor) {
				thiz->first = node;
			}
		}else {
			cursor->next = node;
			node->prev = cursor;
		}
	}while(0);

	dlist_unlock(thiz);

	return ret;
}

Ret dlist_prepend(DList* thiz, void* data)
{
	return dlist_insert(thiz, 0, data);
}

Ret dlist_append(DList* thiz, void* data)
{
	return dlist_insert(thiz, -1, data);
}

Ret dlist_delete(DList* thiz, size_t index)
{
	Ret ret = RET_OK;
	DListNode* cursor = NULL;

	return_val_if_fail(thiz != NULL, RET_INVALID_PARAMS); 
	
	dlist_lock(thiz);
	cursor = dlist_get_node(thiz, index, 0);

	do
	{
		if(cursor == NULL) {
			ret = RET_INVALID_PARAMS;
			break;
		}

		if(cursor != NULL) {
			if(cursor == thiz->first) {
				thiz->first = cursor->next;
			}

			if(cursor->next != NULL) {
				cursor->next->prev = cursor->prev;
			}

			if(cursor->prev != NULL) {
				cursor->prev->next = cursor->next;
			}

			dlist_destroy_node(thiz, cursor);
		}

	}while(0);

	dlist_unlock(thiz);

	return RET_OK;
}

Ret dlist_get_by_index(DList* thiz, size_t index, void** data)
{
	DListNode* cursor = NULL;

	return_val_if_fail(thiz != NULL && data != NULL, RET_INVALID_PARAMS); 

	dlist_lock(thiz);

	cursor = dlist_get_node(thiz, index, 0);

	if(cursor != NULL) {
		*data = cursor->data;
	}
	dlist_unlock(thiz);

	return cursor != NULL ? RET_OK : RET_INVALID_PARAMS;
}

Ret dlist_set_by_index(DList* thiz, size_t index, void* data)
{
	DListNode* cursor = NULL;

	return_val_if_fail(thiz != NULL, RET_INVALID_PARAMS);

	dlist_lock(thiz);
	
	cursor = dlist_get_node(thiz, index, 0);

	if(cursor != NULL) {
		cursor->data = data;
	}

	dlist_unlock(thiz);

	return cursor != NULL ? RET_OK : RET_INVALID_PARAMS;
}

size_t   dlist_length(DList* thiz)
{
	size_t length = 0;
	DListNode* iter = NULL;
	
	return_val_if_fail(thiz != NULL, 0);

	dlist_lock(thiz);

	iter = thiz->first;

	while(iter != NULL) {
		length++;
		iter = iter->next;
	}

	dlist_unlock(thiz);

	return length;
}

Ret dlist_foreach(DList* thiz, DListDataVisitFunc visit, void* ctx)
{
	Ret ret = RET_OK;
	DListNode* iter = NULL;
	
	return_val_if_fail(thiz != NULL && visit != NULL, RET_INVALID_PARAMS);

	dlist_lock(thiz);

	iter = thiz->first;

	while(iter != NULL && ret != RET_STOP) {
		ret = visit(ctx, iter->data);
		iter = iter->next;
	}
	dlist_unlock(thiz);

	return ret;
}

int      dlist_find(DList* thiz, DListDataCompareFunc cmp, void* ctx)
{
	int i = 0;
	DListNode* iter = NULL;

	return_val_if_fail(thiz != NULL && cmp != NULL, -1);

	dlist_lock(thiz);

	iter = thiz->first;
	while(iter != NULL) {
		if(cmp(ctx, iter->data) == 0) {
			break;
		}
		i++;
		iter = iter->next;
	}

	dlist_unlock(thiz);

	return i;
}

void dlist_destroy(DList* thiz)
{
	DListNode* iter = NULL;
	DListNode* next = NULL;
	
	return_if_fail(thiz != NULL);

	dlist_lock(thiz);

	iter = thiz->first;
	while(iter != NULL) {
		next = iter->next;
		dlist_destroy_node(thiz, iter);
		iter = next;
	}

	thiz->first = NULL;
	dlist_destroy_locker(thiz);

	SAFE_FREE(thiz);

	return;
}

#ifdef DLIST_TEST

#include <assert.h>
#include <pthread.h>
#include "locker_pthread.h"
#include "locker_nest.h"

static int cmp_int(void* ctx, void* data)
{
	return (int)data - (int)ctx;
}

static Ret print_int(void* ctx, void* data)
{
	printf("%d ", (int)data);

	return RET_OK;
}

static Ret check_and_dec_int(void* ctx, void* data)
{
	int* expected =(int*)ctx;
	assert(*expected == (int)data);

	(*expected)--;

	return RET_OK;
}

static void test_int_dlist(void)
{
	int i = 0;
	int n = 100;
	int data = 0;
	DList* dlist = dlist_create(NULL, NULL, NULL);

	for(i = 0; i < n; i++){
		assert(dlist_append(dlist, (void*)i) == RET_OK);
		assert(dlist_length(dlist) == (i + 1));
		assert(dlist_get_by_index(dlist, i, (void**)&data) == RET_OK);
		assert(data == i);
		assert(dlist_set_by_index(dlist, i, (void*)(2*i)) == RET_OK);
		assert(dlist_get_by_index(dlist, i, (void**)&data) == RET_OK);
		assert(data == 2*i);
		assert(dlist_set_by_index(dlist, i, (void*)i) == RET_OK);
		assert(dlist_find(dlist, cmp_int, (void*)i) == i);
	}

	for(i = 0; i < n; i++){
		assert(dlist_get_by_index(dlist, 0, (void**)&data) == RET_OK);
		assert(data == (i));
		assert(dlist_length(dlist) == (n-i));
		assert(dlist_delete(dlist, 0) == RET_OK);
		assert(dlist_length(dlist) == (n-i-1));
		if((i + 1) < n){
			assert(dlist_get_by_index(dlist, 0, (void**)&data) == RET_OK);
			assert((int)data == (i+1));
		}
	}
	
	assert(dlist_length(dlist) == 0);

	for(i = 0; i < n; i++){
		assert(dlist_prepend(dlist, (void*)i) == RET_OK);
		assert(dlist_length(dlist) == (i + 1));
		assert(dlist_get_by_index(dlist, 0, (void**)&data) == RET_OK);
		assert(data == i);
		assert(dlist_set_by_index(dlist, 0, (void*)(2*i)) == RET_OK);
		assert(dlist_get_by_index(dlist, 0, (void**)&data) == RET_OK);
		assert(data == 2*i);
		assert(dlist_set_by_index(dlist, 0, (void*)i) == RET_OK);
	}

	i = n - 1;
	assert(dlist_foreach(dlist, check_and_dec_int, &i) == RET_OK);

	dlist_destroy(dlist);

	return;
}

static void test_invalid_params(void)
{
	printf("===========Warning is normal begin==============\n");
	assert(dlist_length(NULL) == 0);
	assert(dlist_prepend(NULL, 0) == RET_INVALID_PARAMS);
	assert(dlist_append(NULL, 0) == RET_INVALID_PARAMS);
	assert(dlist_delete(NULL, 0) == RET_INVALID_PARAMS);
	assert(dlist_insert(NULL, 0, 0) == RET_INVALID_PARAMS);
	assert(dlist_set_by_index(NULL, 0, 0) == RET_INVALID_PARAMS);
	assert(dlist_get_by_index(NULL, 0, NULL) == RET_INVALID_PARAMS);
	assert(dlist_find(NULL, NULL, NULL) < 0);
	assert(dlist_foreach(NULL, NULL, NULL) == RET_INVALID_PARAMS);
	printf("===========Warning is normal end==============\n");

	return;
}

static void single_thread_test(void)
{
	test_int_dlist();
	test_invalid_params();

	return;
}

static void* producer(void* param)
{
	int i = 0;
	DList* dlist = (DList*)param;

	for(i = 0; i < 100; i++){
		assert(dlist_append(dlist, (void*)i) == RET_OK);
	}
	sleep(1);
	for(i = 0; i < 100; i++){
		assert(dlist_prepend(dlist, (void*)i) == RET_OK);
	}

	return NULL;
}

static void* consumer(void* param)
{
	int i = 0;
	DList* dlist = (DList*)param;

	for(i = 0; i < 200; i++){
		usleep(20);
		assert(dlist_delete(dlist, 0) == RET_OK);
	}

	return NULL;
}

static void multi_thread_test(void)
{
	pthread_t consumer_tid = 0;
	pthread_t producer_tid = 0;
	Locker* locker = locker_pthread_create();
	Locker* nest_locker = locker_nest_create(locker, (TaskSelfFunc)pthread_self);
	DList*  dlist = dlist_create(NULL, NULL, nest_locker);
	pthread_create(&producer_tid, NULL, producer, dlist);
	pthread_create(&consumer_tid, NULL, consumer, dlist);

	pthread_join(consumer_tid, NULL);
	pthread_join(producer_tid, NULL);
	dlist_destroy(dlist);

	return;
}
int main(int argc, char* argv[])
{
	single_thread_test();
	multi_thread_test();

	return 0;
}
#endif

CFILES=dlist.c  locker_pthread.c locker_nest.c
all:
	gcc -g -m32 -shared -lpthread $(CFILES) -o libdlist.so
	gcc -g -m32 -DDLIST_TEST  $(CFILES)  -o dlist_test -lpthread

clean:
	rm -f *test *.exe *.so

4.4 读写锁

/*
 * File:    typedef.h
 */

#include <stdio.h>
#include <assert.h>
#include <stdlib.h>

#ifndef TYPEDEF_H
#define TYPEDEF_H

typedef enum _Ret
{
	RET_OK,
	RET_OOM,
	RET_STOP,
	RET_INVALID_PARAMS,
	RET_FAIL
}Ret;

#ifdef __cplusplus
#define DECLS_BEGIN extern "C" {
#define DECLS_END   }
#else
#define DECLS_BEGIN
#define DECLS_END
#endif/*__cplusplus*/

#define return_if_fail(p) if(!(p)) \
	{printf("%s:%d Warning: "#p" failed.\n", \
		__func__, __LINE__); return;}
#define return_val_if_fail(p, ret) if(!(p)) \
	{printf("%s:%d Warning: "#p" failed.\n",\
	__func__, __LINE__); return (ret);}

#define SAFE_FREE(p) if(p != NULL) {free(p); p = NULL;}

#endif/*TYPEDEF_H*/

/*
 * File:    locker.h
 */

#include "typedef.h"

#ifndef LOCKER_H
#define LOCKER_H

DECLS_BEGIN

struct _Locker;
typedef struct _Locker Locker;

typedef Ret  (*LockerLockFunc)(Locker* thiz);
typedef Ret  (*LockerUnlockFunc)(Locker* thiz);
typedef void (*LockerDestroyFunc)(Locker* thiz);

struct _Locker
{
	LockerLockFunc    lock;
	LockerUnlockFunc  unlock;
	LockerDestroyFunc destroy;

	char priv[0];
};

static inline Ret locker_lock(Locker* thiz)
{
	return_val_if_fail(thiz != NULL && thiz->lock != NULL, RET_INVALID_PARAMS);

	return thiz->lock(thiz);
}

static inline Ret locker_unlock(Locker* thiz)
{
	return_val_if_fail(thiz != NULL && thiz->unlock != NULL, RET_INVALID_PARAMS);

	return thiz->unlock(thiz);
}

static inline void locker_destroy(Locker* thiz)
{
	return_if_fail(thiz != NULL && thiz->destroy != NULL);

	thiz->destroy(thiz);

	return;
}

DECLS_END

#endif/*LOCKER_H*/

/*
 * File:    locker_pthread.h
 */

#include "locker.h"

#ifndef LOCKER_PTHREAD_H
#define LOCKER_PTHREAD_H

DECLS_BEGIN

Locker* locker_pthread_create(void);

DECLS_END

#endif/*LOCKER_PTHREAD_H*/

/*
 * File:    locker_pthread.c
 */

#include <stdlib.h>
#include <pthread.h>
#include "locker_pthread.h"

typedef struct _PrivInfo
{
	pthread_mutex_t mutex;
}PrivInfo;

static Ret  locker_pthread_lock(Locker* thiz)
{
	PrivInfo* priv = (PrivInfo*)thiz->priv;

	int ret = pthread_mutex_lock(&priv->mutex);

	return ret == 0 ? RET_OK : RET_FAIL;
}

static Ret  locker_pthread_unlock(Locker* thiz)
{
	PrivInfo* priv = (PrivInfo*)thiz->priv;

	int ret = pthread_mutex_unlock(&priv->mutex);

	return ret == 0 ? RET_OK : RET_FAIL;
}

static void locker_pthread_destroy(Locker* thiz)
{
	PrivInfo* priv = (PrivInfo*)thiz->priv;

	int ret = pthread_mutex_destroy(&priv->mutex);

	SAFE_FREE(thiz);

	return;
}

Locker* locker_pthread_create(void)
{
	Locker* thiz = (Locker*)malloc(sizeof(Locker) + sizeof(PrivInfo));

	if(thiz != NULL)
	{
		PrivInfo* priv = (PrivInfo*)thiz->priv;

		thiz->lock    = locker_pthread_lock;
		thiz->unlock  = locker_pthread_unlock;
		thiz->destroy = locker_pthread_destroy;

		pthread_mutex_init(&(priv->mutex), NULL);
	}

	return thiz;
}


/*
 * File:    locker_nest.h
 */

#include "locker.h"

#ifndef LOCKER_NEST_H
#define LOCKER_NEST_H

DECLS_BEGIN

typedef int (*TaskSelfFunc)(void);
Locker* locker_nest_create(Locker* real_locker, TaskSelfFunc task_self);

DECLS_END

#endif/*LOCKER_NEST_H*/

/*
 * File:    locker_nest.c
 */

#include "locker_nest.h"

typedef struct _PrivInfo
{
	int owner;
	int refcount;
	Locker* real_locker;
	TaskSelfFunc task_self;
}PrivInfo;

static Ret  locker_nest_lock(Locker* thiz)
{
	Ret ret = RET_OK;
	PrivInfo* priv = (PrivInfo*)thiz->priv;

	if(priv->owner == priv->task_self())
	{
		priv->refcount++;
	}
	else
	{
		if( (ret = locker_lock(priv->real_locker)) == RET_OK)
		{
			priv->refcount = 1;
			priv->owner = priv->task_self();
		}
	}

	return ret;
}

static Ret  locker_nest_unlock(Locker* thiz)
{
	Ret ret = RET_OK;
	PrivInfo* priv = (PrivInfo*)thiz->priv;

	return_val_if_fail(priv->owner == priv->task_self(), RET_FAIL);
	
	priv->refcount--;
	if(priv->refcount == 0)
	{
		priv->owner = 0;
		ret = locker_unlock(priv->real_locker);
	}

	return ret;
}

static void  locker_nest_destroy(Locker* thiz)
{
	PrivInfo* priv = (PrivInfo*)thiz->priv;

	priv->owner = 0;
	priv->refcount = 0;
	locker_destroy(priv->real_locker);
	priv->real_locker = NULL;

	SAFE_FREE(thiz);

	return;
}

Locker* locker_nest_create(Locker* real_locker, TaskSelfFunc task_self)
{
	Locker* thiz = NULL;
	return_val_if_fail(real_locker != NULL && task_self != NULL, NULL);
	
	thiz = (Locker*)malloc(sizeof(Locker) + sizeof(PrivInfo));

	if(thiz != NULL)
	{
		PrivInfo* priv = (PrivInfo*)thiz->priv;

		thiz->lock    = locker_nest_lock;
		thiz->unlock  = locker_nest_unlock;
		thiz->destroy = locker_nest_destroy;

		priv->owner = 0;
		priv->refcount = 0;
		priv->real_locker = real_locker;
		priv->task_self = task_self;
	}

	return thiz;
}

/*
 * File:    rw_locker.h
 */

#include "locker.h"

#ifndef RW_LOCKR_H
#define RW_LOCKER_H

struct _RwLocker;
typedef struct _RwLocker RwLocker;

RwLocker* rw_locker_create(Locker* rw_locker, Locker* rd_locker);

Ret rw_locker_wrlock(RwLocker* thiz);
Ret rw_locker_rdlock(RwLocker* thiz);
Ret rw_locker_unlock(RwLocker* thiz);

void rw_locker_destroy(RwLocker* thiz);

#endif/*RW_LOCKER_H*/

/*
 * File:    rw_locker.c
 */

#include "rw_locker.h"

typedef enum _RwLockerMode
{
	RW_LOCKER_NONE,
	RW_LOCKER_WR,
	RW_LOCKER_RD,
	RW_LOCKER_NR
}RwLockerMode;

struct _RwLocker
{
	int readers;
	RwLockerMode mode;
	Locker* rw_locker;
	Locker* rd_locker;
};

RwLocker* rw_locker_create(Locker* rw_locker, Locker* rd_locker)
{
	RwLocker* thiz = NULL;
	return_val_if_fail(rw_locker != NULL && rd_locker != NULL, NULL);

	thiz = (RwLocker*)malloc(sizeof(RwLocker));
	if(thiz != NULL)
	{
		thiz->readers = 0;
		thiz->mode = RW_LOCKER_NONE;
		thiz->rw_locker = rw_locker;
		thiz->rd_locker = rd_locker;
	}

	return thiz;
}

Ret rw_locker_wrlock(RwLocker* thiz)
{
	Ret ret = RET_OK;
	return_val_if_fail(thiz != NULL, RET_INVALID_PARAMS);

	if((ret = locker_lock(thiz->rw_locker)) == RET_OK)
	{
		thiz->mode = RW_LOCKER_WR;
	}

	return ret;
}

Ret rw_locker_rdlock(RwLocker* thiz)
{
	Ret ret = RET_OK;
	return_val_if_fail(thiz != NULL, RET_INVALID_PARAMS);
	
	if((ret = locker_lock(thiz->rd_locker)) == RET_OK)
	{
		thiz->readers++;
		if(thiz->readers == 1)
		{
			ret = locker_lock(thiz->rw_locker);
			thiz->mode = RW_LOCKER_RD;
		}
		locker_unlock(thiz->rd_locker);
	}

	return ret;
}

Ret rw_locker_unlock(RwLocker* thiz)
{
	Ret ret = RET_OK;
	return_val_if_fail(thiz != NULL, RET_INVALID_PARAMS);

	if(thiz->mode == RW_LOCKER_WR)
	{
		thiz->mode == RW_LOCKER_NONE;
		ret = locker_unlock(thiz->rw_locker);
	}
	else
	{
		assert(thiz->mode == RW_LOCKER_RD);
		if((ret = locker_lock(thiz->rd_locker)) == RET_OK)
		{
			thiz->readers--;
			if(thiz->readers == 0)
			{
				thiz->mode == RW_LOCKER_NONE;
				ret = locker_unlock(thiz->rw_locker);
			}
			locker_unlock(thiz->rd_locker);
		}
	}

	return ret;
}

void rw_locker_destroy(RwLocker* thiz)
{
	if(thiz != NULL)
	{
		locker_destroy(thiz->rd_locker);
		locker_destroy(thiz->rw_locker);
		thiz->rd_locker = thiz->rw_locker = NULL;
		SAFE_FREE(thiz);
	}

	return;
}


/*
 * File:    dlist.h
 */

#include <stdio.h>
#include "rw_locker.h"

#ifndef DLIST_H
#define DLIST_H

DECLS_BEGIN

struct _DList;
typedef struct _DList DList;

typedef void     (*DListDataDestroyFunc)(void* ctx, void* data);
typedef int      (*DListDataCompareFunc)(void* ctx, void* data);
typedef Ret      (*DListDataVisitFunc)(void* ctx, void* data);

DList* dlist_create(DListDataDestroyFunc data_destroy, void* ctx, RwLocker* rw_locker);

Ret dlist_insert(DList* thiz, size_t index, void* data);
Ret dlist_prepend(DList* thiz, void* data);
Ret dlist_append(DList* thiz, void* data);
Ret dlist_delete(DList* thiz, size_t index);
Ret dlist_get_by_index(DList* thiz, size_t index, void** data);
Ret dlist_set_by_index(DList* thiz, size_t index, void* data);
size_t   dlist_length(DList* thiz);
int      dlist_find(DList* thiz, DListDataCompareFunc cmp, void* ctx);
Ret      dlist_foreach(DList* thiz, DListDataVisitFunc visit, void* ctx);

void dlist_destroy(DList* thiz);

DECLS_END

#endif/*DLIST*/

/*
 * File:    dlist.c
 */


#include <stdlib.h>
#include <unistd.h>
#include "dlist.h"

typedef struct _DListNode
{
	struct _DListNode* prev;
	struct _DListNode* next;

	void* data;
}DListNode;

struct _DList
{
	RwLocker* rw_locker;
	DListNode* first;
	void* data_destroy_ctx;
	DListDataDestroyFunc data_destroy;
};

size_t dlist_length_nolock(DList* thiz);

static void dlist_destroy_data(DList* thiz, void* data)
{
	if(thiz->data_destroy != NULL)
	{
		thiz->data_destroy(thiz->data_destroy_ctx, data);
	}

	return;
}

static DListNode* dlist_create_node(DList* thiz, void* data)
{
	DListNode* node = malloc(sizeof(DListNode));

	if(node != NULL)
	{
		node->prev = NULL;
		node->next = NULL;
		node->data = data;
	}

	return node;
}

static void dlist_destroy_node(DList* thiz, DListNode* node)
{
	if(node != NULL)
	{
		node->next = NULL;
		node->prev = NULL;
		dlist_destroy_data(thiz, node->data);
		SAFE_FREE(node);
	}

	return;
}

static void dlist_wrlock(DList* thiz)
{
	if(thiz->rw_locker != NULL)
	{
		rw_locker_wrlock(thiz->rw_locker);
	}

	return;
}

static void dlist_rdlock(DList* thiz)
{
	if(thiz->rw_locker != NULL)
	{
		rw_locker_rdlock(thiz->rw_locker);
	}

	return;
}

static void dlist_unlock(DList* thiz)
{
	if(thiz->rw_locker != NULL)
	{
		rw_locker_unlock(thiz->rw_locker);
	}

	return;
}

static void dlist_destroy_locker(DList* thiz)
{
	if(thiz->rw_locker != NULL)
	{
		rw_locker_unlock(thiz->rw_locker);
		rw_locker_destroy(thiz->rw_locker);
	}

	return;
}

DList* dlist_create(DListDataDestroyFunc data_destroy, void* ctx, RwLocker* rw_locker)
{
	DList* thiz = malloc(sizeof(DList));

	if(thiz != NULL)
	{
		thiz->first  = NULL;
		thiz->rw_locker = rw_locker;
		thiz->data_destroy = data_destroy;
		thiz->data_destroy_ctx = ctx;
	}

	return thiz;
}

static DListNode* dlist_get_node(DList* thiz, size_t index, int fail_return_last)
{
	DListNode* iter = NULL;
	
	return_val_if_fail(thiz != NULL, NULL); 

	iter = thiz->first;

	while(iter != NULL && iter->next != NULL && index > 0)
	{
		iter = iter->next;
		index--;
	}

	if(!fail_return_last)
	{
		iter = index > 0 ? NULL : iter;
	}

	return iter;
}

Ret dlist_insert(DList* thiz, size_t index, void* data)
{
	Ret ret = RET_OK;
	DListNode* node = NULL;
	DListNode* cursor = NULL;

	return_val_if_fail(thiz != NULL, RET_INVALID_PARAMS); 

	dlist_wrlock(thiz);

	do
	{
		if((node = dlist_create_node(thiz, data)) == NULL)
		{
			ret = RET_OOM;
			break;
		}

		if(thiz->first == NULL)
		{
			thiz->first = node;
			break;
		}

		cursor = dlist_get_node(thiz, index, 1);
		
		if(index < dlist_length_nolock(thiz))
		{
			node->next = cursor;
			if(cursor->prev != NULL)
			{
				cursor->prev->next = node;
			}
			cursor->prev = node;
			if(thiz->first == cursor)
			{
				thiz->first = node;
			}
		}
		else
		{
			cursor->next = node;
			node->prev = cursor;
		}
	}while(0);

	dlist_unlock(thiz);

	return ret;
}

Ret dlist_prepend(DList* thiz, void* data)
{
	return dlist_insert(thiz, 0, data);
}

Ret dlist_append(DList* thiz, void* data)
{
	return dlist_insert(thiz, -1, data);
}

Ret dlist_delete(DList* thiz, size_t index)
{
	Ret ret = RET_OK;
	DListNode* cursor = NULL;

	return_val_if_fail(thiz != NULL, RET_INVALID_PARAMS); 
	
	dlist_wrlock(thiz);
	cursor = dlist_get_node(thiz, index, 0);

	do
	{
		if(cursor == NULL)
		{
			ret = RET_INVALID_PARAMS;
			break;
		}

		if(cursor != NULL)
		{
			if(cursor == thiz->first)
			{
				thiz->first = cursor->next;
			}

			if(cursor->next != NULL)
			{
				cursor->next->prev = cursor->prev;
			}

			if(cursor->prev != NULL)
			{
				cursor->prev->next = cursor->next;
			}

			dlist_destroy_node(thiz, cursor);
		}

	}while(0);

	dlist_unlock(thiz);

	return RET_OK;
}

Ret dlist_get_by_index(DList* thiz, size_t index, void** data)
{
	DListNode* cursor = NULL;

	return_val_if_fail(thiz != NULL && data != NULL, RET_INVALID_PARAMS); 

	dlist_rdlock(thiz);

	cursor = dlist_get_node(thiz, index, 0);

	if(cursor != NULL)
	{
		*data = cursor->data;
	}
	dlist_unlock(thiz);

	return cursor != NULL ? RET_OK : RET_INVALID_PARAMS;
}

Ret dlist_set_by_index(DList* thiz, size_t index, void* data)
{
	DListNode* cursor = NULL;

	return_val_if_fail(thiz != NULL, RET_INVALID_PARAMS);

	dlist_wrlock(thiz);
	
	cursor = dlist_get_node(thiz, index, 0);

	if(cursor != NULL)
	{
		cursor->data = data;
	}

	dlist_unlock(thiz);

	return cursor != NULL ? RET_OK : RET_INVALID_PARAMS;
}

size_t dlist_length_nolock(DList* thiz)
{
	size_t length = 0;
	DListNode* iter = NULL;

	iter = thiz->first;

	while(iter != NULL)
	{
		length++;
		iter = iter->next;
	}

	return length;
}

size_t   dlist_length(DList* thiz)
{
	size_t length = 0;
	
	return_val_if_fail(thiz != NULL, 0);

	dlist_rdlock(thiz);
	
	length = dlist_length_nolock(thiz);

	dlist_unlock(thiz);

	return length;
}

Ret dlist_foreach(DList* thiz, DListDataVisitFunc visit, void* ctx)
{
	Ret ret = RET_OK;
	DListNode* iter = NULL;
	
	return_val_if_fail(thiz != NULL && visit != NULL, RET_INVALID_PARAMS);

	dlist_rdlock(thiz);

	iter = thiz->first;

	while(iter != NULL && ret != RET_STOP)
	{
		ret = visit(ctx, iter->data);

		iter = iter->next;
	}
	dlist_unlock(thiz);

	return ret;
}

int      dlist_find(DList* thiz, DListDataCompareFunc cmp, void* ctx)
{
	int i = 0;
	DListNode* iter = NULL;

	return_val_if_fail(thiz != NULL && cmp != NULL, -1);

	dlist_rdlock(thiz);

	iter = thiz->first;
	while(iter != NULL)
	{
		if(cmp(ctx, iter->data) == 0)
		{
			break;
		}
		i++;
		iter = iter->next;
	}

	dlist_unlock(thiz);

	return i;
}

void dlist_destroy(DList* thiz)
{
	DListNode* iter = NULL;
	DListNode* next = NULL;
	
	return_if_fail(thiz != NULL);

	dlist_wrlock(thiz);

	iter = thiz->first;
	while(iter != NULL)
	{
		next = iter->next;
		dlist_destroy_node(thiz, iter);
		iter = next;
	}

	thiz->first = NULL;
	dlist_destroy_locker(thiz);
	
	SAFE_FREE(thiz);

	return;
}

#ifdef DLIST_TEST

#include <assert.h>
#include <pthread.h>
#include "locker_pthread.h"
#include "locker_nest.h"

static int cmp_int(void* ctx, void* data)
{
	return (int)data - (int)ctx;
}

static Ret print_int(void* ctx, void* data)
{
	printf("%d ", (int)data);

	return RET_OK;
}

static Ret check_and_dec_int(void* ctx, void* data)
{
	int* expected =(int*)ctx;
	assert(*expected == (int)data);

	(*expected)--;

	return RET_OK;
}

static void test_int_dlist(void)
{
	int i = 0;
	int n = 100;
	int data = 0;
	DList* dlist = dlist_create(NULL, NULL, NULL);

	for(i = 0; i < n; i++)
	{
		assert(dlist_append(dlist, (void*)i) == RET_OK);
		assert(dlist_length(dlist) == (i + 1));
		assert(dlist_get_by_index(dlist, i, (void**)&data) == RET_OK);
		assert(data == i);
		assert(dlist_set_by_index(dlist, i, (void*)(2*i)) == RET_OK);
		assert(dlist_get_by_index(dlist, i, (void**)&data) == RET_OK);
		assert(data == 2*i);
		assert(dlist_set_by_index(dlist, i, (void*)i) == RET_OK);
		assert(dlist_find(dlist, cmp_int, (void*)i) == i);
	}

	for(i = 0; i < n; i++)
	{
		assert(dlist_get_by_index(dlist, 0, (void**)&data) == RET_OK);
		assert(data == (i));
		assert(dlist_length(dlist) == (n-i));
		assert(dlist_delete(dlist, 0) == RET_OK);
		assert(dlist_length(dlist) == (n-i-1));
		if((i + 1) < n)
		{
			assert(dlist_get_by_index(dlist, 0, (void**)&data) == RET_OK);
			assert((int)data == (i+1));
		}
	}
	
	assert(dlist_length(dlist) == 0);

	for(i = 0; i < n; i++)
	{
		assert(dlist_prepend(dlist, (void*)i) == RET_OK);
		assert(dlist_length(dlist) == (i + 1));
		assert(dlist_get_by_index(dlist, 0, (void**)&data) == RET_OK);
		assert(data == i);
		assert(dlist_set_by_index(dlist, 0, (void*)(2*i)) == RET_OK);
		assert(dlist_get_by_index(dlist, 0, (void**)&data) == RET_OK);
		assert(data == 2*i);
		assert(dlist_set_by_index(dlist, 0, (void*)i) == RET_OK);
	}

	i = n - 1;
	assert(dlist_foreach(dlist, check_and_dec_int, &i) == RET_OK);

	dlist_destroy(dlist);

	return;
}

static void test_invalid_params(void)
{
	printf("===========Warning is normal begin==============\n");
	assert(dlist_length(NULL) == 0);
	assert(dlist_prepend(NULL, 0) == RET_INVALID_PARAMS);
	assert(dlist_append(NULL, 0) == RET_INVALID_PARAMS);
	assert(dlist_delete(NULL, 0) == RET_INVALID_PARAMS);
	assert(dlist_insert(NULL, 0, 0) == RET_INVALID_PARAMS);
	assert(dlist_set_by_index(NULL, 0, 0) == RET_INVALID_PARAMS);
	assert(dlist_get_by_index(NULL, 0, NULL) == RET_INVALID_PARAMS);
	assert(dlist_find(NULL, NULL, NULL) < 0);
	assert(dlist_foreach(NULL, NULL, NULL) == RET_INVALID_PARAMS);
	printf("===========Warning is normal end==============\n");

	return;
}

static void single_thread_test(void)
{
	test_int_dlist();
	test_invalid_params();

	return;
}

#define NR 1000
static void* producer(void* param)
{
	int i = 0;
	DList* dlist = (DList*)param;

	for(i = 0; i < NR; i++)
	{
		assert(dlist_append(dlist, (void*)i) == RET_OK);
	}
	sleep(1);
	for(i = 0; i < NR; i++)
	{
		assert(dlist_prepend(dlist, (void*)i) == RET_OK);
	}
	for(i = 0; i < NR; i++)
	{
		assert(dlist_insert(dlist, i, (void*)i) == RET_OK);
	}

	return NULL;
}

static void* consumer(void* param)
{
	int i = 0;
	DList* dlist = (DList*)param;

	for(i = 0; i < 3 * NR; i++)
	{
		usleep(20);
		assert(dlist_delete(dlist, 0) == RET_OK);
	}

	return NULL;
}

static void* reader(void* param)
{
	int i = 0;
	DList* dlist = (DList*)param;

	for(i = 0; i < NR; i++)
	{
		int length = dlist_length(dlist);
		dlist_find(dlist, cmp_int, (void*)i);
	}

	return NULL;
}

static void multi_thread_test(void)
{
	pthread_t consumer_tid = 0;
	pthread_t producer_tid = 0;
	pthread_t reader_tid = 0;
	Locker* rw_locker = locker_pthread_create();
	Locker* rd_locker = locker_pthread_create();
	DList* dlist = dlist_create(NULL, NULL,
		rw_locker_create(rw_locker, rd_locker));

	pthread_create(&producer_tid, NULL, producer, dlist);
	pthread_create(&consumer_tid, NULL, consumer, dlist);
	pthread_create(&reader_tid, NULL, reader, dlist);

	pthread_join(consumer_tid, NULL);
	pthread_join(producer_tid, NULL);
	pthread_join(reader_tid, NULL);
	printf("length=%d\n", dlist_length(dlist));
	dlist_destroy(dlist);

	return;
}
int main(int argc, char* argv[])
{
	single_thread_test();
	multi_thread_test();

	return 0;
}
#endif

CFILES=dlist.c  locker_pthread.c locker_nest.c rw_locker.c
all:
	gcc -g -m32  -shared -lpthread $(CFILES) -o libdlist.so
	gcc -g -m32 -DDLIST_TEST  $(CFILES) -o dlist_test -lpthread

clean:
	rm -f *test *.exe *.so

4.5 无锁数据结构

/*
 * File:    typedef.h
 */

#include <stdio.h>
#include <assert.h>
#include <stdlib.h>

#ifndef TYPEDEF_H
#define TYPEDEF_H

typedef enum _Ret
{
	RET_OK,
	RET_OOM,
	RET_STOP,
	RET_INVALID_PARAMS,
	RET_FAIL
}Ret;

#ifdef __cplusplus
#define DECLS_BEGIN extern "C" {
#define DECLS_END   }
#else
#define DECLS_BEGIN
#define DECLS_END
#endif/*__cplusplus*/

#define return_if_fail(p) if(!(p)) \
	{printf("%s:%d Warning: "#p" failed.\n", \
		__func__, __LINE__); return;}
#define return_val_if_fail(p, ret) if(!(p)) \
	{printf("%s:%d Warning: "#p" failed.\n",\
	__func__, __LINE__); return (ret);}

#define SAFE_FREE(p) if(p != NULL) {free(p); p = NULL;}

#endif/*TYPEDEF_H*/

/*
 * File:    fifo_ring.c
 */

#include "typedef.h"

typedef struct _FifoRing
{
	int r_cursor;
	int w_cursor;
	size_t length;
	void* data[0];
	
}FifoRing;

FifoRing* fifo_ring_create(size_t length)
{
	FifoRing* thiz = NULL;
	
	return_val_if_fail(length > 1, NULL);

	thiz = (FifoRing*)malloc(sizeof(FifoRing) + length * sizeof(void*));

	if(thiz != NULL) {
		thiz->r_cursor = 0;
		thiz->w_cursor = 0;
		thiz->length   = length;
	}

	return thiz;
}

Ret fifo_ring_pop(FifoRing* thiz, void** data)
{
	Ret ret = RET_FAIL;
	return_val_if_fail(thiz != NULL && data != NULL, RET_FAIL);

	if(thiz->r_cursor != thiz->w_cursor) {
		*data = thiz->data[thiz->r_cursor];
		thiz->r_cursor = (thiz->r_cursor + 1)%thiz->length;

		ret = RET_OK;
	}

	return ret;
}

Ret fifo_ring_push(FifoRing* thiz, void* data)    
{
	int w_cursor = 0;
	Ret ret = RET_FAIL;
	return_val_if_fail(thiz != NULL, RET_FAIL);

	w_cursor = (thiz->w_cursor + 1) % thiz->length;
	
	if(w_cursor != thiz->r_cursor) {
		thiz->data[thiz->w_cursor] = data;
		thiz->w_cursor = w_cursor;

		ret = RET_OK;
	}

	return ret;
}

void fifo_ring_destroy(FifoRing* thiz)
{
	if(thiz != NULL) {
		free(thiz);
	}

	return;
}

#ifdef FIFO_RING_TEST
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

//#define NR 1000000
#define NR 1000

static void* thread_push(void* param)
{
	int i = 0;
	FifoRing* fifo = (FifoRing*)param;

	while(i < NR) {
		if(fifo_ring_push(fifo, (void*)i) == RET_OK) {
			i++;
		}else{
			usleep(10);
		}
	}

	return NULL;
}

static void* thread_pop(void* param)
{
	int i = 0;
	void* data = 0;
	FifoRing* fifo = (FifoRing*)param;

	while(i < NR) {
		if(fifo_ring_pop(fifo, (void**)&data) == RET_OK) {
			assert(i == (int)data);
			i++;
		}else{
			usleep(10);
		}
	}

	return NULL;
}

void push_pop_test(size_t fifo_length)
{
	pthread_t push_tid = 0;
	pthread_t pop_tid = 0;
	FifoRing* fifo = fifo_ring_create(fifo_length);

	pthread_create(&push_tid, NULL, thread_push, fifo);
	pthread_create(&pop_tid, NULL, thread_pop, fifo);

	pthread_join(push_tid, NULL);
	pthread_join(pop_tid, NULL);

	fifo_ring_destroy(fifo);
	
	return;
}

int main(int argc, char* argv[])
{
	push_pop_test(2);
	push_pop_test(20);
	push_pop_test(200);
	push_pop_test(2000);

	return 0;
}

#endif/*FIFO_RING_TEST*/

/*
 * File:    dlist.h
 */

#include <stdio.h>
#include "locker.h"

#ifndef DLIST_H
#define DLIST_H

DECLS_BEGIN

struct _DList;
typedef struct _DList DList;

typedef void     (*DListDataDestroyFunc)(void* ctx, void* data);
typedef int      (*DListDataCompareFunc)(void* ctx, void* data);
typedef Ret      (*DListDataVisitFunc)(void* ctx, void* data);

DList* dlist_create(DListDataDestroyFunc data_destroy, void* ctx, Locker* locker);

Ret dlist_insert(DList* thiz, size_t index, void* data);
Ret dlist_prepend(DList* thiz, void* data);
Ret dlist_append(DList* thiz, void* data);
Ret dlist_delete(DList* thiz, size_t index);
Ret dlist_get_by_index(DList* thiz, size_t index, void** data);
Ret dlist_set_by_index(DList* thiz, size_t index, void* data);
size_t   dlist_length(DList* thiz);
int      dlist_find(DList* thiz, DListDataCompareFunc cmp, void* ctx);
Ret      dlist_foreach(DList* thiz, DListDataVisitFunc visit, void* ctx);

void dlist_destroy(DList* thiz);

DECLS_END

#endif/*DLIST*/

/*
 * File:    swmr_dlist.c
 */

#include <unistd.h>
#include "dlist.h"
#include "iatomic.h"

#define CAS(_a, _o, _n)                                    \
({ __typeof__(_o) __o = _o;                                \
   __asm__ __volatile__(                                   \
       "lock cmpxchg %3,%1"                                \
       : "=a" (__o), "=m" (*(volatile unsigned int *)(_a)) \
       :  "0" (__o), "r" (_n) );                           \
   __o;                                                    \
})

typedef struct _SwmrDList
{
	atomic_t rd_index_and_ref;
	DList* dlists[2];
}SwmrDList;

void swmr_dlist_destroy(SwmrDList* thiz);

SwmrDList* swmr_dlist_create(DListDataDestroyFunc data_destroy, void* ctx)
{
	Ret ret = RET_FAIL;
	SwmrDList* thiz = (SwmrDList*)calloc(1, sizeof(SwmrDList));

	do
	{
		if((thiz->dlists[0] = dlist_create(data_destroy, ctx, NULL)) == NULL) {
			break;
		}
	
		if((thiz->dlists[1] = dlist_create(data_destroy, ctx, NULL)) == NULL) {
			break;
		}

		ret = RET_OK;
	}while(0);

	if(ret != RET_OK) {
		swmr_dlist_destroy(thiz);
		thiz = NULL;
	}

	return thiz;
}

void swmr_dlist_destroy(SwmrDList* thiz)
{
	if(thiz != NULL) {
		if(thiz->dlists != NULL) {
			dlist_destroy(thiz->dlists[0]);
			dlist_destroy(thiz->dlists[1]);
			thiz->dlists[0] = NULL;
			thiz->dlists[1] = NULL;
		}
		free(thiz);
	}

	return;
}

int swmr_dlist_find(SwmrDList* thiz, DListDataCompareFunc cmp, void* ctx)
{
	int ret = 0;
	return_val_if_fail(thiz != NULL && thiz->dlists != NULL, -1);

	atomic_inc(&(thiz->rd_index_and_ref));
	size_t rd_index = (thiz->rd_index_and_ref.counter>>24) & 0x1;
	ret = dlist_find(thiz->dlists[rd_index], cmp, ctx);
	atomic_dec(&(thiz->rd_index_and_ref));

	return ret;
}

int swmr_dlist_length(SwmrDList* thiz)
{
	int ret = 0;
	return_val_if_fail(thiz != NULL && thiz->dlists != NULL, -1);

	atomic_inc(&(thiz->rd_index_and_ref));
	size_t rd_index = (thiz->rd_index_and_ref.counter>>24) & 0x1;
	ret = dlist_length(thiz->dlists[rd_index]);
	atomic_dec(&(thiz->rd_index_and_ref));

	return ret;
}

Ret swmr_dlist_insert(SwmrDList* thiz, size_t index, void* data)
{
	Ret ret = RET_FAIL;
	DList* wr_dlist = NULL;
	return_val_if_fail(thiz != NULL && thiz->dlists != NULL, ret);

	size_t wr_index = !((thiz->rd_index_and_ref.counter>>24) & 0x1);
	if((ret = dlist_insert(thiz->dlists[wr_index], index, data)) == RET_OK) {
		int rd_index_old = thiz->rd_index_and_ref.counter & 0xFF000000;
		int rd_index_new = wr_index << 24;

		do
		{
			usleep(100);
		}while(CAS(&(thiz->rd_index_and_ref), rd_index_old, rd_index_new));
		
		wr_index = rd_index_old>>24;
		ret = dlist_insert(thiz->dlists[wr_index], index, data);
	}

	return ret;
}

Ret swmr_dlist_delete(SwmrDList* thiz, size_t index)
{
	Ret ret = RET_FAIL;
	DList* wr_dlist = NULL;
	return_val_if_fail(thiz != NULL && thiz->dlists != NULL, ret);

	size_t wr_index = !((thiz->rd_index_and_ref.counter>>24) & 0x1);
	if((ret = dlist_delete(thiz->dlists[wr_index], index)) == RET_OK) {
		int rd_index_old = thiz->rd_index_and_ref.counter & 0xFF000000;
		int rd_index_new = wr_index << 24;

		do
		{
			usleep(100);
		}while(CAS(&(thiz->rd_index_and_ref), rd_index_old, rd_index_new));
		
		wr_index = rd_index_old>>24;
		ret = dlist_delete(thiz->dlists[wr_index], index);
	}

	return ret;
}

#ifdef SWMR_DLIST_TEST
#include <pthread.h>
#define NR 1000
static int cmp_int(void* ctx, void* data)
{
	return (int)data - (int)ctx;
}
static void* reader(void* param)
{
	int i = 0;
	int j = 0;
	size_t length = 0;
	SwmrDList* swmr = (SwmrDList*)param;

	for(j = 0; j < NR; j++) {
		for(i = 0; i < swmr_dlist_length(swmr); i++) {
			assert(swmr_dlist_find(swmr, cmp_int, (void*)i) == i);
		}
	}

	return NULL;
}

static void* writer(void* param)
{
	int i = 0;
	SwmrDList* swmr = (SwmrDList*)param;

	for(i = 0; i < NR; i++) {
		swmr_dlist_insert(swmr, i, (void*)i);
	}
	
	for(; i>0; i--) {
		swmr_dlist_delete(swmr, i);
	}

	return NULL;
}

#define RD_NR 100

int main(int argc, char* argv[])
{
	int i = 0;
	pthread_t wr_tid = 0;
	pthread_t rd_tids[RD_NR] = {0};
	SwmrDList* swmr = swmr_dlist_create(NULL, NULL);

	pthread_create(&wr_tid, NULL, writer, swmr);
	for(i = 0; i < RD_NR; i++) {
		pthread_create(rd_tids+i, NULL, reader, swmr);
	}
	
	for(i = 0; i < RD_NR; i++) {
		pthread_join(rd_tids[i], NULL);
	}

	pthread_join(wr_tid, NULL);

	return 0;
}
#endif/*SWMR_DLIST_TEST*/

#ifndef __ALSA_IATOMIC_H
#define __ALSA_IATOMIC_H

#if defined(__i386__) || defined(__x86_64__)

/*
 * Atomic operations that C can't guarantee us.  Useful for
 * resource counting etc..
 */

#define ATOMIC_SMP_LOCK "lock ; "

/*
 * Make sure gcc doesn't try to be clever and move things around
 * on us. We need to use _exactly_ the address the user gave us,
 * not some alias that contains the same information.
 */
typedef struct { volatile int counter; } atomic_t;

#define ATOMIC_INIT(i)	{ (i) }

/**
 * atomic_read - read atomic variable
 * @v: pointer of type atomic_t
 * 
 * Atomically reads the value of @v.  Note that the guaranteed
 * useful range of an atomic_t is only 24 bits.
 */ 
#define atomic_read(v)		((v)->counter)

/**
 * atomic_set - set atomic variable
 * @v: pointer of type atomic_t
 * @i: required value
 * 
 * Atomically sets the value of @v to @i.  Note that the guaranteed
 * useful range of an atomic_t is only 24 bits.
 */ 
#define atomic_set(v,i)		(((v)->counter) = (i))

/**
 * atomic_add - add integer to atomic variable
 * @i: integer value to add
 * @v: pointer of type atomic_t
 * 
 * Atomically adds @i to @v.  Note that the guaranteed useful range
 * of an atomic_t is only 24 bits.
 */
static __inline__ void atomic_add(int i, atomic_t *v)
{
	__asm__ __volatile__(
		ATOMIC_SMP_LOCK "addl %1,%0"
		:"=m" (v->counter)
		:"ir" (i), "m" (v->counter));
}

/**
 * atomic_sub - subtract the atomic variable
 * @i: integer value to subtract
 * @v: pointer of type atomic_t
 * 
 * Atomically subtracts @i from @v.  Note that the guaranteed
 * useful range of an atomic_t is only 24 bits.
 */
static __inline__ void atomic_sub(int i, atomic_t *v)
{
	__asm__ __volatile__(
		ATOMIC_SMP_LOCK "subl %1,%0"
		:"=m" (v->counter)
		:"ir" (i), "m" (v->counter));
}

/**
 * atomic_sub_and_test - subtract value from variable and test result
 * @i: integer value to subtract
 * @v: pointer of type atomic_t
 * 
 * Atomically subtracts @i from @v and returns
 * true if the result is zero, or false for all
 * other cases.  Note that the guaranteed
 * useful range of an atomic_t is only 24 bits.
 */
static __inline__ int atomic_sub_and_test(int i, atomic_t *v)
{
	unsigned char c;

	__asm__ __volatile__(
		ATOMIC_SMP_LOCK "subl %2,%0; sete %1"
		:"=m" (v->counter), "=qm" (c)
		:"ir" (i), "m" (v->counter) : "memory");
	return c;
}

/**
 * atomic_inc - increment atomic variable
 * @v: pointer of type atomic_t
 * 
 * Atomically increments @v by 1.  Note that the guaranteed
 * useful range of an atomic_t is only 24 bits.
 */ 
static __inline__ void atomic_inc(atomic_t *v)
{
	__asm__ __volatile__(
		ATOMIC_SMP_LOCK "incl %0"
		:"=m" (v->counter)
		:"m" (v->counter));
}

/**
 * atomic_dec - decrement atomic variable
 * @v: pointer of type atomic_t
 * 
 * Atomically decrements @v by 1.  Note that the guaranteed
 * useful range of an atomic_t is only 24 bits.
 */ 
static __inline__ void atomic_dec(atomic_t *v)
{
	__asm__ __volatile__(
		ATOMIC_SMP_LOCK "decl %0"
		:"=m" (v->counter)
		:"m" (v->counter));
}

/**
 * atomic_dec_and_test - decrement and test
 * @v: pointer of type atomic_t
 * 
 * Atomically decrements @v by 1 and
 * returns true if the result is 0, or false for all other
 * cases.  Note that the guaranteed
 * useful range of an atomic_t is only 24 bits.
 */ 
static __inline__ int atomic_dec_and_test(atomic_t *v)
{
	unsigned char c;

	__asm__ __volatile__(
		ATOMIC_SMP_LOCK "decl %0; sete %1"
		:"=m" (v->counter), "=qm" (c)
		:"m" (v->counter) : "memory");
	return c != 0;
}

/**
 * atomic_inc_and_test - increment and test 
 * @v: pointer of type atomic_t
 * 
 * Atomically increments @v by 1
 * and returns true if the result is zero, or false for all
 * other cases.  Note that the guaranteed
 * useful range of an atomic_t is only 24 bits.
 */ 
static __inline__ int atomic_inc_and_test(atomic_t *v)
{
	unsigned char c;

	__asm__ __volatile__(
		ATOMIC_SMP_LOCK "incl %0; sete %1"
		:"=m" (v->counter), "=qm" (c)
		:"m" (v->counter) : "memory");
	return c != 0;
}

/**
 * atomic_add_negative - add and test if negative
 * @v: pointer of type atomic_t
 * @i: integer value to add
 * 
 * Atomically adds @i to @v and returns true
 * if the result is negative, or false when
 * result is greater than or equal to zero.  Note that the guaranteed
 * useful range of an atomic_t is only 24 bits.
 */ 
static __inline__ int atomic_add_negative(int i, atomic_t *v)
{
	unsigned char c;

	__asm__ __volatile__(
		ATOMIC_SMP_LOCK "addl %2,%0; sets %1"
		:"=m" (v->counter), "=qm" (c)
		:"ir" (i), "m" (v->counter) : "memory");
	return c;
}

/* These are x86-specific, used by some header files */
#define atomic_clear_mask(mask, addr) \
__asm__ __volatile__(ATOMIC_SMP_LOCK "andl %0,%1" \
: : "r" (~(mask)),"m" (*addr) : "memory")

#define atomic_set_mask(mask, addr) \
__asm__ __volatile__(ATOMIC_SMP_LOCK "orl %0,%1" \
: : "r" (mask),"m" (*addr) : "memory")

/*
 * Force strict CPU ordering.
 * And yes, this is required on UP too when we're talking
 * to devices.
 *
 * For now, "wmb()" doesn't actually do anything, as all
 * Intel CPU's follow what Intel calls a *Processor Order*,
 * in which all writes are seen in the program order even
 * outside the CPU.
 *
 * I expect future Intel CPU's to have a weaker ordering,
 * but I'd also expect them to finally get their act together
 * and add some real memory barriers if so.
 */
 
#ifdef __i386__
#define mb() 	__asm__ __volatile__ ("lock; addl $0,0(%%esp)": : :"memory")
#define rmb()	mb()
#define wmb()	__asm__ __volatile__ ("": : :"memory")
#else
#define mb() 	asm volatile("mfence":::"memory")
#define rmb()	asm volatile("lfence":::"memory")
#define wmb()	asm volatile("sfence":::"memory")
#endif

#undef ATOMIC_SMP_LOCK

#define IATOMIC_DEFINED		1

#endif /* __i386__ */

#ifdef __ia64__

/*
 * On IA-64, counter must always be volatile to ensure that that the
 * memory accesses are ordered.
 */
typedef struct { volatile int counter; } atomic_t;

#define ATOMIC_INIT(i)		((atomic_t) { (i) })

#define atomic_read(v)		((v)->counter)
#define atomic_set(v,i)		(((v)->counter) = (i))

/* stripped version - we need only 4byte version */
#define ia64_cmpxchg(sem,ptr,old,new,size) \
({ \
	__typeof__(ptr) _p_ = (ptr); \
	__typeof__(new) _n_ = (new); \
	unsigned long _o_, _r_; \
	_o_ = (unsigned int) (long) (old); \
	__asm__ __volatile__ ("mov ar.ccv=%0;;" :: "rO"(_o_)); \
	__asm__ __volatile__ ("cmpxchg4."sem" %0=[%1],%2,ar.ccv" \
			      : "=r"(_r_) : "r"(_p_), "r"(_n_) : "memory"); \
	(__typeof__(old)) _r_; \
})

static __inline__ int
ia64_atomic_add (int i, atomic_t *v)
{
	int old, new;
	// CMPXCHG_BUGCHECK_DECL

	do {
		// CMPXCHG_BUGCHECK(v);
		old = atomic_read(v);
		new = old + i;
	} while (ia64_cmpxchg("acq", v, old, old + i, sizeof(atomic_t)) != old);
	return new;
}

static __inline__ int
ia64_atomic_sub (int i, atomic_t *v)
{
	int old, new;
	// CMPXCHG_BUGCHECK_DECL

	do {
		// CMPXCHG_BUGCHECK(v);
		old = atomic_read(v);
		new = old - i;
	} while (ia64_cmpxchg("acq", v, old, new, sizeof(atomic_t)) != old);
	return new;
}

#define IA64_FETCHADD(tmp,v,n,sz)						\
({										\
	switch (sz) {								\
	      case 4:								\
		__asm__ __volatile__ ("fetchadd4.rel %0=[%1],%2"		\
				      : "=r"(tmp) : "r"(v), "i"(n) : "memory");	\
		break;								\
										\
	      case 8:								\
		__asm__ __volatile__ ("fetchadd8.rel %0=[%1],%2"		\
				      : "=r"(tmp) : "r"(v), "i"(n) : "memory");	\
		break;								\
	}									\
})

#define ia64_fetch_and_add(i,v)							\
({										\
	unsigned long _tmp;								\
	volatile __typeof__(*(v)) *_v = (v);					\
	switch (i) {								\
	      case -16:	IA64_FETCHADD(_tmp, _v, -16, sizeof(*(v))); break;	\
	      case  -8:	IA64_FETCHADD(_tmp, _v,  -8, sizeof(*(v))); break;	\
	      case  -4:	IA64_FETCHADD(_tmp, _v,  -4, sizeof(*(v))); break;	\
	      case  -1:	IA64_FETCHADD(_tmp, _v,  -1, sizeof(*(v))); break;	\
	      case   1:	IA64_FETCHADD(_tmp, _v,   1, sizeof(*(v))); break;	\
	      case   4:	IA64_FETCHADD(_tmp, _v,   4, sizeof(*(v))); break;	\
	      case   8:	IA64_FETCHADD(_tmp, _v,   8, sizeof(*(v))); break;	\
	      case  16:	IA64_FETCHADD(_tmp, _v,  16, sizeof(*(v))); break;	\
	}									\
	(__typeof__(*v)) (_tmp + (i));	/* return new value */			\
})

/*
 * Atomically add I to V and return TRUE if the resulting value is
 * negative.
 */
static __inline__ int
atomic_add_negative (int i, atomic_t *v)
{
	return ia64_atomic_add(i, v) < 0;
}

#define atomic_add_return(i,v)						\
	((__builtin_constant_p(i) &&					\
	  (   (i ==  1) || (i ==  4) || (i ==  8) || (i ==  16)		\
	   || (i == -1) || (i == -4) || (i == -8) || (i == -16)))	\
	 ? ia64_fetch_and_add(i, &(v)->counter)				\
	 : ia64_atomic_add(i, v))

#define atomic_sub_return(i,v)						\
	((__builtin_constant_p(i) &&					\
	  (   (i ==  1) || (i ==  4) || (i ==  8) || (i ==  16)		\
	   || (i == -1) || (i == -4) || (i == -8) || (i == -16)))	\
	 ? ia64_fetch_and_add(-(i), &(v)->counter)			\
	 : ia64_atomic_sub(i, v))

#define atomic_dec_return(v)		atomic_sub_return(1, (v))
#define atomic_inc_return(v)		atomic_add_return(1, (v))

#define atomic_sub_and_test(i,v)	(atomic_sub_return((i), (v)) == 0)
#define atomic_dec_and_test(v)		(atomic_sub_return(1, (v)) == 0)
#define atomic_inc_and_test(v)		(atomic_add_return(1, (v)) != 0)

#define atomic_add(i,v)			atomic_add_return((i), (v))
#define atomic_sub(i,v)			atomic_sub_return((i), (v))
#define atomic_inc(v)			atomic_add(1, (v))
#define atomic_dec(v)			atomic_sub(1, (v))

/*
 * Macros to force memory ordering.  In these descriptions, "previous"
 * and "subsequent" refer to program order; "visible" means that all
 * architecturally visible effects of a memory access have occurred
 * (at a minimum, this means the memory has been read or written).
 *
 *   wmb():	Guarantees that all preceding stores to memory-
 *		like regions are visible before any subsequent
 *		stores and that all following stores will be
 *		visible only after all previous stores.
 *   rmb():	Like wmb(), but for reads.
 *   mb():	wmb()/rmb() combo, i.e., all previous memory
 *		accesses are visible before all subsequent
 *		accesses and vice versa.  This is also known as
 *		a "fence."
 *
 * Note: "mb()" and its variants cannot be used as a fence to order
 * accesses to memory mapped I/O registers.  For that, mf.a needs to
 * be used.  However, we don't want to always use mf.a because (a)
 * it's (presumably) much slower than mf and (b) mf.a is supported for
 * sequential memory pages only.
 */
#define mb()	__asm__ __volatile__ ("mf" ::: "memory")
#define rmb()	mb()
#define wmb()	mb()

#define IATOMIC_DEFINED		1

#endif /* __ia64__ */

#ifdef __alpha__

/*
 * Atomic operations that C can't guarantee us.  Useful for
 * resource counting etc...
 *
 * But use these as seldom as possible since they are much slower
 * than regular operations.
 */


/*
 * Counter is volatile to make sure gcc doesn't try to be clever
 * and move things around on us. We need to use _exactly_ the address
 * the user gave us, not some alias that contains the same information.
 */
typedef struct { volatile int counter; } atomic_t;

#define ATOMIC_INIT(i)	( (atomic_t) { (i) } )

#define atomic_read(v)		((v)->counter)
#define atomic_set(v,i)		((v)->counter = (i))

/*
 * To get proper branch prediction for the main line, we must branch
 * forward to code at the end of this object's .text section, then
 * branch back to restart the operation.
 */

static __inline__ void atomic_add(int i, atomic_t * v)
{
	unsigned long temp;
	__asm__ __volatile__(
	"1:	ldl_l %0,%1\n"
	"	addl %0,%2,%0\n"
	"	stl_c %0,%1\n"
	"	beq %0,2f\n"
	".subsection 2\n"
	"2:	br 1b\n"
	".previous"
	:"=&r" (temp), "=m" (v->counter)
	:"Ir" (i), "m" (v->counter));
}

static __inline__ void atomic_sub(int i, atomic_t * v)
{
	unsigned long temp;
	__asm__ __volatile__(
	"1:	ldl_l %0,%1\n"
	"	subl %0,%2,%0\n"
	"	stl_c %0,%1\n"
	"	beq %0,2f\n"
	".subsection 2\n"
	"2:	br 1b\n"
	".previous"
	:"=&r" (temp), "=m" (v->counter)
	:"Ir" (i), "m" (v->counter));
}

/*
 * Same as above, but return the result value
 */
static __inline__ long atomic_add_return(int i, atomic_t * v)
{
	long temp, result;
	__asm__ __volatile__(
	"1:	ldl_l %0,%1\n"
	"	addl %0,%3,%2\n"
	"	addl %0,%3,%0\n"
	"	stl_c %0,%1\n"
	"	beq %0,2f\n"
	"	mb\n"
	".subsection 2\n"
	"2:	br 1b\n"
	".previous"
	:"=&r" (temp), "=m" (v->counter), "=&r" (result)
	:"Ir" (i), "m" (v->counter) : "memory");
	return result;
}

static __inline__ long atomic_sub_return(int i, atomic_t * v)
{
	long temp, result;
	__asm__ __volatile__(
	"1:	ldl_l %0,%1\n"
	"	subl %0,%3,%2\n"
	"	subl %0,%3,%0\n"
	"	stl_c %0,%1\n"
	"	beq %0,2f\n"
	"	mb\n"
	".subsection 2\n"
	"2:	br 1b\n"
	".previous"
	:"=&r" (temp), "=m" (v->counter), "=&r" (result)
	:"Ir" (i), "m" (v->counter) : "memory");
	return result;
}

#define atomic_dec_return(v) atomic_sub_return(1,(v))
#define atomic_inc_return(v) atomic_add_return(1,(v))

#define atomic_sub_and_test(i,v) (atomic_sub_return((i), (v)) == 0)
#define atomic_dec_and_test(v) (atomic_sub_return(1, (v)) == 0)

#define atomic_inc(v) atomic_add(1,(v))
#define atomic_dec(v) atomic_sub(1,(v))

#define mb() \
__asm__ __volatile__("mb": : :"memory")

#define rmb() \
__asm__ __volatile__("mb": : :"memory")

#define wmb() \
__asm__ __volatile__("wmb": : :"memory")

#define IATOMIC_DEFINED		1

#endif /* __alpha__ */

#ifdef __powerpc__

typedef struct { volatile int counter; } atomic_t;

#define ATOMIC_INIT(i)	{ (i) }

#define atomic_read(v)		((v)->counter)
#define atomic_set(v,i)		(((v)->counter) = (i))

extern void atomic_clear_mask(unsigned long mask, unsigned long *addr);
extern void atomic_set_mask(unsigned long mask, unsigned long *addr);

#define SMP_ISYNC	"\n\tisync"

static __inline__ void atomic_add(int a, atomic_t *v)
{
	int t;

	__asm__ __volatile__(
"1:	lwarx	%0,0,%3		# atomic_add\n\
	add	%0,%2,%0\n\
	stwcx.	%0,0,%3\n\
	bne-	1b"
	: "=&r" (t), "=m" (v->counter)
	: "r" (a), "r" (&v->counter), "m" (v->counter)
	: "cc");
}

static __inline__ int atomic_add_return(int a, atomic_t *v)
{
	int t;

	__asm__ __volatile__(
"1:	lwarx	%0,0,%2		# atomic_add_return\n\
	add	%0,%1,%0\n\
	stwcx.	%0,0,%2\n\
	bne-	1b"
	SMP_ISYNC
	: "=&r" (t)
	: "r" (a), "r" (&v->counter)
	: "cc", "memory");

	return t;
}

static __inline__ void atomic_sub(int a, atomic_t *v)
{
	int t;

	__asm__ __volatile__(
"1:	lwarx	%0,0,%3		# atomic_sub\n\
	subf	%0,%2,%0\n\
	stwcx.	%0,0,%3\n\
	bne-	1b"
	: "=&r" (t), "=m" (v->counter)
	: "r" (a), "r" (&v->counter), "m" (v->counter)
	: "cc");
}

static __inline__ int atomic_sub_return(int a, atomic_t *v)
{
	int t;

	__asm__ __volatile__(
"1:	lwarx	%0,0,%2		# atomic_sub_return\n\
	subf	%0,%1,%0\n\
	stwcx.	%0,0,%2\n\
	bne-	1b"
	SMP_ISYNC
	: "=&r" (t)
	: "r" (a), "r" (&v->counter)
	: "cc", "memory");

	return t;
}

static __inline__ void atomic_inc(atomic_t *v)
{
	int t;

	__asm__ __volatile__(
"1:	lwarx	%0,0,%2		# atomic_inc\n\
	addic	%0,%0,1\n\
	stwcx.	%0,0,%2\n\
	bne-	1b"
	: "=&r" (t), "=m" (v->counter)
	: "r" (&v->counter), "m" (v->counter)
	: "cc");
}

static __inline__ int atomic_inc_return(atomic_t *v)
{
	int t;

	__asm__ __volatile__(
"1:	lwarx	%0,0,%1		# atomic_inc_return\n\
	addic	%0,%0,1\n\
	stwcx.	%0,0,%1\n\
	bne-	1b"
	SMP_ISYNC
	: "=&r" (t)
	: "r" (&v->counter)
	: "cc", "memory");

	return t;
}

static __inline__ void atomic_dec(atomic_t *v)
{
	int t;

	__asm__ __volatile__(
"1:	lwarx	%0,0,%2		# atomic_dec\n\
	addic	%0,%0,-1\n\
	stwcx.	%0,0,%2\n\
	bne-	1b"
	: "=&r" (t), "=m" (v->counter)
	: "r" (&v->counter), "m" (v->counter)
	: "cc");
}

static __inline__ int atomic_dec_return(atomic_t *v)
{
	int t;

	__asm__ __volatile__(
"1:	lwarx	%0,0,%1		# atomic_dec_return\n\
	addic	%0,%0,-1\n\
	stwcx.	%0,0,%1\n\
	bne-	1b"
	SMP_ISYNC
	: "=&r" (t)
	: "r" (&v->counter)
	: "cc", "memory");

	return t;
}

#define atomic_sub_and_test(a, v)	(atomic_sub_return((a), (v)) == 0)
#define atomic_dec_and_test(v)		(atomic_dec_return((v)) == 0)

/*
 * Atomically test *v and decrement if it is greater than 0.
 * The function returns the old value of *v minus 1.
 */
static __inline__ int atomic_dec_if_positive(atomic_t *v)
{
	int t;

	__asm__ __volatile__(
"1:	lwarx	%0,0,%1		# atomic_dec_if_positive\n\
	addic.	%0,%0,-1\n\
	blt-	2f\n\
	stwcx.	%0,0,%1\n\
	bne-	1b"
	SMP_ISYNC
	"\n\
2:"	: "=&r" (t)
	: "r" (&v->counter)
	: "cc", "memory");

	return t;
}

/*
 * Memory barrier.
 * The sync instruction guarantees that all memory accesses initiated
 * by this processor have been performed (with respect to all other
 * mechanisms that access memory).  The eieio instruction is a barrier
 * providing an ordering (separately) for (a) cacheable stores and (b)
 * loads and stores to non-cacheable memory (e.g. I/O devices).
 *
 * mb() prevents loads and stores being reordered across this point.
 * rmb() prevents loads being reordered across this point.
 * wmb() prevents stores being reordered across this point.
 *
 * We can use the eieio instruction for wmb, but since it doesn't
 * give any ordering guarantees about loads, we have to use the
 * stronger but slower sync instruction for mb and rmb.
 */
#define mb()  __asm__ __volatile__ ("sync" : : : "memory")
#define rmb()  __asm__ __volatile__ ("sync" : : : "memory")
#define wmb()  __asm__ __volatile__ ("eieio" : : : "memory")

#define IATOMIC_DEFINED		1

#endif /* __powerpc__ */

#ifdef __mips__

typedef struct { volatile int counter; } atomic_t;

#define ATOMIC_INIT(i)    { (i) }

/*
 * atomic_read - read atomic variable
 * @v: pointer of type atomic_t
 *
 * Atomically reads the value of @v.  Note that the guaranteed
 * useful range of an atomic_t is only 24 bits.
 */
#define atomic_read(v)	((v)->counter)

/*
 * atomic_set - set atomic variable
 * @v: pointer of type atomic_t
 * @i: required value
 *
 * Atomically sets the value of @v to @i.  Note that the guaranteed
 * useful range of an atomic_t is only 24 bits.
 */
#define atomic_set(v,i)	((v)->counter = (i))

/*
 * for MIPS II and better we can use ll/sc instruction, and kernel 2.4.3+
 * will emulate it on MIPS I.
 */

/*
 * atomic_add - add integer to atomic variable
 * @i: integer value to add
 * @v: pointer of type atomic_t
 *
 * Atomically adds @i to @v.  Note that the guaranteed useful range
 * of an atomic_t is only 24 bits.
 */
extern __inline__ void atomic_add(int i, atomic_t * v)
{
	unsigned long temp;

	__asm__ __volatile__(
		".set push                            \n"
		".set mips2                           \n"
		"1:   ll      %0, %1      # atomic_add\n"
		"     addu    %0, %2                  \n"
		"     sc      %0, %1                  \n"
		"     beqz    %0, 1b                  \n"
		".set pop                             \n"
		: "=&r" (temp), "=m" (v->counter)
		: "Ir" (i), "m" (v->counter));
}

/*
 * atomic_sub - subtract the atomic variable
 * @i: integer value to subtract
 * @v: pointer of type atomic_t
 *
 * Atomically subtracts @i from @v.  Note that the guaranteed
 * useful range of an atomic_t is only 24 bits.
 */
extern __inline__ void atomic_sub(int i, atomic_t * v)
{
	unsigned long temp;

	__asm__ __volatile__(
		".set push                            \n"
		".set mips2                           \n"
		"1:   ll      %0, %1      # atomic_sub\n"
		"     subu    %0, %2                  \n"
		"     sc      %0, %1                  \n"
		"     beqz    %0, 1b                  \n"
		".set pop                             \n"
		: "=&r" (temp), "=m" (v->counter)
		: "Ir" (i), "m" (v->counter));
}

/*
 * Same as above, but return the result value
 */
extern __inline__ int atomic_add_return(int i, atomic_t * v)
{
	unsigned long temp, result;

	__asm__ __volatile__(
		".set push               # atomic_add_return\n"
		".set noreorder                             \n"
		".set mips2                                 \n"
		"1:   ll      %1, %2                        \n"
		"     addu    %0, %1, %3                    \n"
		"     sc      %0, %2                        \n"
		"     beqz    %0, 1b                        \n"
		"     addu    %0, %1, %3                    \n"
		".set pop                                   \n"
		: "=&r" (result), "=&r" (temp), "=m" (v->counter)
		: "Ir" (i), "m" (v->counter)
		: "memory");

	return result;
}

extern __inline__ int atomic_sub_return(int i, atomic_t * v)
{
	unsigned long temp, result;

	__asm__ __volatile__(
		".set push                                   \n"
		".set mips2                                  \n"
		".set noreorder           # atomic_sub_return\n"
		"1:   ll    %1, %2                           \n"
		"     subu  %0, %1, %3                       \n"
		"     sc    %0, %2                           \n"
		"     beqz  %0, 1b                           \n"
		"     subu  %0, %1, %3                       \n"
		".set pop                                    \n"
		: "=&r" (result), "=&r" (temp), "=m" (v->counter)
		: "Ir" (i), "m" (v->counter)
		: "memory");

	return result;
}

#define atomic_dec_return(v) atomic_sub_return(1,(v))
#define atomic_inc_return(v) atomic_add_return(1,(v))

/*
 * atomic_sub_and_test - subtract value from variable and test result
 * @i: integer value to subtract
 * @v: pointer of type atomic_t
 *
 * Atomically subtracts @i from @v and returns
 * true if the result is zero, or false for all
 * other cases.  Note that the guaranteed
 * useful range of an atomic_t is only 24 bits.
 */
#define atomic_sub_and_test(i,v) (atomic_sub_return((i), (v)) == 0)

/*
 * atomic_inc_and_test - increment and test
 * @v: pointer of type atomic_t
 *
 * Atomically increments @v by 1
 * and returns true if the result is zero, or false for all
 * other cases.  Note that the guaranteed
 * useful range of an atomic_t is only 24 bits.
 */
#define atomic_inc_and_test(v) (atomic_inc_return(1, (v)) == 0)

/*
 * atomic_dec_and_test - decrement by 1 and test
 * @v: pointer of type atomic_t
 *
 * Atomically decrements @v by 1 and
 * returns true if the result is 0, or false for all other
 * cases.  Note that the guaranteed
 * useful range of an atomic_t is only 24 bits.
 */
#define atomic_dec_and_test(v) (atomic_sub_return(1, (v)) == 0)

/*
 * atomic_inc - increment atomic variable
 * @v: pointer of type atomic_t
 *
 * Atomically increments @v by 1.  Note that the guaranteed
 * useful range of an atomic_t is only 24 bits.
 */
#define atomic_inc(v) atomic_add(1,(v))

/*
 * atomic_dec - decrement and test
 * @v: pointer of type atomic_t
 *
 * Atomically decrements @v by 1.  Note that the guaranteed
 * useful range of an atomic_t is only 24 bits.
 */
#define atomic_dec(v) atomic_sub(1,(v))

/*
 * atomic_add_negative - add and test if negative
 * @v: pointer of type atomic_t
 * @i: integer value to add
 *
 * Atomically adds @i to @v and returns true
 * if the result is negative, or false when
 * result is greater than or equal to zero.  Note that the guaranteed
 * useful range of an atomic_t is only 24 bits.
 *
 * Currently not implemented for MIPS.
 */

#define mb()						\
__asm__ __volatile__(					\
	"# prevent instructions being moved around\n\t"	\
	".set\tnoreorder\n\t"				\
	"# 8 nops to fool the R4400 pipeline\n\t"	\
	"nop;nop;nop;nop;nop;nop;nop;nop\n\t"		\
	".set\treorder"					\
	: /* no output */				\
	: /* no input */				\
	: "memory")
#define rmb() mb()
#define wmb() mb()

#define IATOMIC_DEFINED		1

#endif /* __mips__ */

#ifdef __arm__

/*
 * FIXME: bellow code is valid only for SA11xx
 */

/*
 * Save the current interrupt enable state & disable IRQs
 */
#define local_irq_save(x)					\
	({							\
		unsigned long temp;				\
	__asm__ __volatile__(					\
	"mrs	%0, cpsr		@ local_irq_save\n"	\
"	orr	%1, %0, #128\n"					\
"	msr	cpsr_c, %1"					\
	: "=r" (x), "=r" (temp)					\
	:							\
	: "memory");						\
	})

/*
 * restore saved IRQ & FIQ state
 */
#define local_irq_restore(x)					\
	__asm__ __volatile__(					\
	"msr	cpsr_c, %0		@ local_irq_restore\n"	\
	:							\
	: "r" (x)						\
	: "memory")

#define __save_flags_cli(x) local_irq_save(x)
#define __restore_flags(x) local_irq_restore(x)

typedef struct { volatile int counter; } atomic_t;

#define ATOMIC_INIT(i)	{ (i) }

#define atomic_read(v)	((v)->counter)
#define atomic_set(v,i)	(((v)->counter) = (i))

static __inline__ void atomic_add(int i, volatile atomic_t *v)
{
	unsigned long flags;

	__save_flags_cli(flags);
	v->counter += i;
	__restore_flags(flags);
}

static __inline__ void atomic_sub(int i, volatile atomic_t *v)
{
	unsigned long flags;

	__save_flags_cli(flags);
	v->counter -= i;
	__restore_flags(flags);
}

static __inline__ void atomic_inc(volatile atomic_t *v)
{
	unsigned long flags;

	__save_flags_cli(flags);
	v->counter += 1;
	__restore_flags(flags);
}

static __inline__ void atomic_dec(volatile atomic_t *v)
{
	unsigned long flags;

	__save_flags_cli(flags);
	v->counter -= 1;
	__restore_flags(flags);
}

static __inline__ int atomic_dec_and_test(volatile atomic_t *v)
{
	unsigned long flags;
	int result;

	__save_flags_cli(flags);
	v->counter -= 1;
	result = (v->counter == 0);
	__restore_flags(flags);

	return result;
}

static inline int atomic_add_negative(int i, volatile atomic_t *v)
{
	unsigned long flags;
	int result;

	__save_flags_cli(flags);
	v->counter += i;
	result = (v->counter < 0);
	__restore_flags(flags);

	return result;
}

static __inline__ void atomic_clear_mask(unsigned long mask, unsigned long *addr)
{
	unsigned long flags;

	__save_flags_cli(flags);
	*addr &= ~mask;
	__restore_flags(flags);
}

#define mb() __asm__ __volatile__ ("" : : : "memory")
#define rmb() mb()
#define wmb() mb()

#define IATOMIC_DEFINED		1

#endif /* __arm__ */

#ifndef IATOMIC_DEFINED
/*
 * non supported architecture.
 */
#warning "Atomic operations are not supported on this architecture."

typedef struct { volatile int counter; } atomic_t;

#define ATOMIC_INIT(i)	{ (i) }

#define atomic_read(v)	((v)->counter)
#define atomic_set(v,i)	(((v)->counter) = (i))
#define atomic_add(i,v) (((v)->counter) += (i))
#define atomic_sub(i,v) (((v)->counter) -= (i))
#define atomic_inc(v)   (((v)->counter)++)
#define atomic_dec(v)   (((v)->counter)--)

#define mb()
#define rmb()
#define wmb()

#define IATOMIC_DEFINED		1

#endif /* IATOMIC_DEFINED */

/*
 *  Atomic read/write
 *  Copyright (c) 2001 by Abramo Bagnara <abramo@alsa-project.org>
 */

/* Max number of times we must spin on a spin-lock calling sched_yield().
   After MAX_SPIN_COUNT iterations, we put the calling thread to sleep. */

#ifndef MAX_SPIN_COUNT
#define MAX_SPIN_COUNT 50
#endif

/* Duration of sleep (in nanoseconds) when we can't acquire a spin-lock
   after MAX_SPIN_COUNT iterations of sched_yield().
   This MUST BE > 2ms.
   (Otherwise the kernel does busy-waiting for real-time threads,
    giving other threads no chance to run.) */

#ifndef SPIN_SLEEP_DURATION
#define SPIN_SLEEP_DURATION 2000001
#endif

typedef struct {
	unsigned int begin, end;
} snd_atomic_write_t;

typedef struct {
	volatile const snd_atomic_write_t *write;
	unsigned int end;
} snd_atomic_read_t;

void snd_atomic_read_wait(snd_atomic_read_t *t);

static inline void snd_atomic_write_init(snd_atomic_write_t *w)
{
	w->begin = 0;
	w->end = 0;
}

static inline void snd_atomic_write_begin(snd_atomic_write_t *w)
{
	w->begin++;
	wmb();
}

static inline void snd_atomic_write_end(snd_atomic_write_t *w)
{
	wmb();
	w->end++;
}

static inline void snd_atomic_read_init(snd_atomic_read_t *r, snd_atomic_write_t *w)
{
	r->write = w;
}

static inline void snd_atomic_read_begin(snd_atomic_read_t *r)
{
	r->end = r->write->end;
	rmb();
}

static inline int snd_atomic_read_ok(snd_atomic_read_t *r)
{
	rmb();
	return r->end == r->write->begin;
}

#endif /* __ALSA_IATOMIC_H */
/*
 * File:    atomic.c
 */

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include "iatomic.h"

#ifdef ATOMIC_TEST

atomic_t g_count = {0};

static void* thread_inc(void* param)
{
	int i = 0;
	for(i = 0; i < 1000000; i++){
		atomic_inc(&g_count);
	}

	return NULL;
}

static void* thread_dec(void* param)
{
	int i = 0;
	for(i = 0; i < 1000000; i++){
		atomic_dec(&g_count);
	}

	return NULL;
}

int main(int argc, char* argv[])
{
	pthread_t inc_tid = 0;
	pthread_t dec_tid = 0;

	pthread_create(&inc_tid, NULL, thread_inc, NULL);
	pthread_create(&dec_tid, NULL, thread_dec, NULL);

	pthread_join(inc_tid, NULL);
	pthread_join(dec_tid, NULL);

	printf("count=%d\n", g_count.counter);

	return 0;
}
#endif/*ATOMIC_TEST*/
all:
	gcc -g -m32 fifo_ring.c  -DFIFO_RING_TEST -o fifo_ring_test -lpthread
	gcc -g -m32 swmr_dlist.c dlist.c -DSWMR_DLIST_TEST -o swmr_dlist_test -lpthread
	gcc -g -m32 atomic.c -lpthread -DATOMIC_TEST -o atomic_test
clean:
	rm -f *test