Index: server/fen-thread-pool.c
===================================================================
--- server/fen-thread-pool.c	(revision 0)
+++ server/fen-thread-pool.c	(revision 0)
@@ -0,0 +1,216 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim:set expandtab ts=4 shiftwidth=4: */
+
+#include <strings.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "fen-thread-pool.h"
+
+typedef struct thread_data th_data_t;
+
+struct thread_pool_data {
+	pthread_t *threads;
+	pthread_mutex_t q_mutex;	/* protect the queue */
+	pthread_cond_t q_cond;
+	th_data_t *q_head;		/* queue of data */
+	th_data_t *q_tail;
+	long q_len;
+
+	// pthread_mutex_t mutex;	 protect the following
+	long max_t;
+	long max_q;
+};
+
+struct thread_data {
+	thp_run_cb run;
+	thp_data_destroy_cb destroy;
+	void *data;
+	struct thread_data *prev;
+	struct thread_data *next;
+};
+
+static void *thread_run (void * data);
+#define MUTEX_LOCK(lock) \
+do { \
+	if (pthread_mutex_lock(&lock) != 0) { \
+		abort (); \
+	} \
+} while (0)
+#define MUTEX_UNLOCK(lock) \
+do { \
+	if (pthread_mutex_unlock(&lock) != 0) { \
+		abort (); \
+	} \
+} while (0)
+
+static void *
+thread_run (void * data)
+{
+	thp_t *tp = (thp_t *) data;
+	int ret;
+	th_data_t *td = NULL;
+
+	for (;;) {
+        MUTEX_LOCK (tp->q_mutex);
+		while (tp->q_len == 0) {
+			if ((ret = pthread_cond_wait(&tp->q_cond, &tp->q_mutex)) != 0) {
+				perror ("thread_run - pthread_cond_wait");
+				exit (1);
+			}
+		}
+
+		td = tp->q_head;
+		if (--tp->q_len == 0) {
+			tp->q_head = tp->q_tail = NULL;
+		} else {
+			tp->q_head = td->next;
+			tp->q_head->prev = NULL;
+		}
+		
+        MUTEX_UNLOCK (tp->q_mutex);
+
+		/* run task */
+		td->run (td->data);
+		if (td->destroy) {
+			td->destroy (td->data);
+		}
+		free (td);
+		td = NULL;
+	}
+}
+
+/**
+ * Create a thread pool, returns the pointer. Return NULL if failed.
+ */
+
+extern thp_t *
+thread_pool_new (int max_thread_num, int max_queue_num)
+{
+	thp_t *tp;
+	int i, ret;
+
+	tp = (thp_t *) calloc (1, sizeof (thp_t));
+	if (tp == NULL)
+		return NULL;
+
+	tp->max_t = max_thread_num;
+	tp->max_q = max_queue_num;
+	if ((ret = pthread_mutex_init (&tp->q_mutex, NULL)) != 0) {
+		perror ("thread_pool_new - pthread_mutex_init");
+		free (tp);
+		return NULL;
+	}
+	if ((ret = pthread_cond_init(&tp->q_cond, NULL)) != 0) {
+		perror ("thread_pool_new - pthread_cond_init");
+		if (pthread_mutex_destroy (&tp->q_mutex) != 0) {
+			perror ("thread_pool_new - pthread_mutex_destroy");
+		}
+		free (tp);
+		return NULL;
+	}
+	tp->threads = (pthread_t *) calloc (max_thread_num, sizeof(pthread_t));
+	if (tp->threads == NULL) {
+		free (tp);
+		return NULL;
+	}
+	for (i = 0; i < max_thread_num; i++) {
+		if (pthread_create (&tp->threads[i], NULL,
+				    thread_run,
+				    (void *)tp) != 0) {
+			perror ("thread_pool_new - pthread_create");
+			exit (1);
+		}
+	}
+	return tp;
+}
+
+/**
+ * Dostroy a thread pool.
+ *
+ * (Not finished yet, shouldn't be invoked.)
+ */
+
+extern void
+thread_pool_destroy (thp_t *tp, int wait)
+{
+	int i;
+	/* clean the queue first */
+	/* clean up the resources */
+	if (pthread_mutex_destroy (&tp->q_mutex) != 0) {
+		perror ("pthread_mutex_destroy");
+	}
+	if (pthread_cond_destroy (&tp->q_cond) != 0) {
+		perror ("pthread_cond_destroy");
+	}
+	for (i = 0; i < tp->max_t; i++) {
+		pthread_join (tp->threads[i], NULL);
+	}
+	free (tp);
+}
+
+/**
+ * Run a task via run_cb.
+ * Returns 0 if successful.
+ */
+
+extern int
+thread_pool_run (thp_t *tp, thp_run_cb run_cb, void *data)
+{
+	return thread_pool_run_full (tp, run_cb, data, NULL);
+}
+
+/**
+ * Run a task via run_cb. After run_cb, the data will destroyed by destroy_cb.
+ * Returns 0 if successful.
+ */
+
+extern int
+thread_pool_run_full (thp_t *tp,
+		      thp_run_cb run_cb,
+		      void *data,
+		      thp_data_destroy_cb destroy_cb)
+{
+	th_data_t *td = NULL;
+	int ret;
+
+	if ((td = (th_data_t *) calloc (1, sizeof (th_data_t))) == NULL) {
+		return errno;
+	}
+
+	td->run = run_cb;
+	td->data = data;
+	td->destroy = destroy_cb;
+
+	/* ready for adding */
+    MUTEX_LOCK (tp->q_mutex);
+
+	if (tp->q_len >= tp->max_q) {
+		/* is full */
+        MUTEX_UNLOCK (tp->q_mutex);
+		free (td);
+		return tp->max_q;
+	}
+
+	if (tp->q_len == 0) {
+		tp->q_tail = tp->q_head = td;
+	} else {
+		td->prev = tp->q_tail;
+		tp->q_tail->next = td;
+		tp->q_tail = td;
+	}
+	tp->q_len ++;
+
+	if ((ret = pthread_cond_broadcast(&tp->q_cond)) != 0) {
+		perror ("thread_pool_run_full - pthread_cond_wait");
+		abort ();
+	}
+
+    MUTEX_UNLOCK (tp->q_mutex);
+
+	return 0;
+}
