Index: /trunk/ChangeLog
===================================================================
--- /trunk/ChangeLog	(revision 1198)
+++ /trunk/ChangeLog	(revision 1199)
@@ -7,4 +7,5 @@
  * improve compatibility with "the ionCube PHP Loader", Zend Optimizer
  * fix random crash when cache is reinitialized yet failed (Thanks to Brad Baker for generating crash dump)
+ * fix ZTS thead safe
 
 3.0.0 2012-10-29
Index: /trunk/NEWS
===================================================================
--- /trunk/NEWS	(revision 1198)
+++ /trunk/NEWS	(revision 1199)
@@ -3,4 +3,5 @@
 ========
  * bug fixes
+ * fix ZTS thead safe
  * improve compatibility with "the ionCube PHP Loader", Zend Optimizer
  * improve stability
Index: /trunk/mod_cacher/xc_cacher.c
===================================================================
--- /trunk/mod_cacher/xc_cacher.c	(revision 1198)
+++ /trunk/mod_cacher/xc_cacher.c	(revision 1199)
@@ -2656,5 +2656,5 @@
 			CHECK(cache->cached->phps = allocator->vtable->calloc(allocator, hphp->size, sizeof(xc_entry_data_php_t*)), "phps OOM");
 		}
-		CHECK(cache->lck              = xc_lock_init(NULL), "can't create lock");
+		CHECK(cache->lck              = xc_lock_init(NULL, 0), "can't create lock");
 
 		cache->hcache  = hcache;
Index: /trunk/xcache/xc_lock.c
===================================================================
--- /trunk/xcache/xc_lock.c	(revision 1198)
+++ /trunk/xcache/xc_lock.c	(revision 1199)
@@ -6,4 +6,8 @@
 #ifdef ZEND_WIN32
 #	include <process.h>
+#else
+#	include <unistd.h>
+#	include <fcntl.h>
+#	include <errno.h>
 #endif
 
@@ -23,20 +27,17 @@
 		NULL)
 #endif
-#include "xc_lock.h"
-
-struct _xc_lock_t {
+
+typedef struct {
 	HANDLE fd;
 	char *pathname;
-};
-
+} xc_fcntl_lock_t;
+
+/* {{{ fcntl lock impl */
 #ifndef ZEND_WIN32
-#	include <unistd.h>
-#	include <fcntl.h>
-#	include <errno.h>
 #	define LCK_WR F_WRLCK
 #	define LCK_RD F_RDLCK
 #	define LCK_UN F_UNLCK
 #	define LCK_NB 0
-static inline int dolock(xc_lock_t *lck, int type) /* {{{ */
+static inline int dolock(xc_fcntl_lock_t *lck, int type)
 {
 	int ret;
@@ -54,5 +55,4 @@
 	return ret;
 }
-/* }}} */
 #else
 
@@ -69,5 +69,5 @@
 #	define LCK_UN 0
 #	define LCK_NB LOCKFILE_FAIL_IMMEDIATELY
-static inline int dolock(xc_lock_t *lck, int type) /* {{{ */
+static inline int dolock(xc_fcntl_lock_t *lck, int type)
 {
 	static OVERLAPPED offset = {0, 0, 0, 0, NULL};
@@ -80,11 +80,10 @@
 	}
 }
-/* }}} */
-#endif
-
-xc_lock_t *xc_fcntl_init(const char *pathname) /* {{{ */
+#endif
+/* }}} */
+
+static zend_bool xc_fcntl_init(xc_fcntl_lock_t *lck, const char *pathname) /* {{{ */
 {
 	HANDLE fd;
-	xc_lock_t *lck;
 	int size;
 	char *myname;
@@ -114,5 +113,4 @@
 
 	if (fd != INVALID_HANDLE_VALUE) {
-		lck = malloc(sizeof(lck[0]));
 
 #ifndef __CYGWIN__
@@ -133,8 +131,8 @@
 	}
 
-	return lck;
-}
-/* }}} */
-void xc_fcntl_destroy(xc_lock_t *lck) /* {{{ */
+	return lck ? 1 : 0;
+}
+/* }}} */
+static void xc_fcntl_destroy(xc_fcntl_lock_t *lck) /* {{{ */
 {
 	close(lck->fd);
@@ -143,8 +141,7 @@
 #endif
 	free(lck->pathname);
-	free(lck);
-}
-/* }}} */
-void xc_fcntl_lock(xc_lock_t *lck) /* {{{ */
+}
+/* }}} */
+static void xc_fcntl_lock(xc_fcntl_lock_t *lck) /* {{{ */
 {
 	if (dolock(lck, LCK_WR) < 0) {
@@ -153,5 +150,5 @@
 }
 /* }}} */
-void xc_fcntl_rdlock(xc_lock_t *lck) /* {{{ */
+static void xc_fcntl_rdlock(xc_fcntl_lock_t *lck) /* {{{ */
 {
 	if (dolock(lck, LCK_RD) < 0) {
@@ -160,5 +157,5 @@
 }
 /* }}} */
-void xc_fcntl_unlock(xc_lock_t *lck) /* {{{ */
+static void xc_fcntl_unlock(xc_fcntl_lock_t *lck) /* {{{ */
 {
 	if (dolock(lck, LCK_UN) < 0) {
@@ -167,2 +164,134 @@
 }
 /* }}} */
+
+#undef XC_INTERPROCESS_LOCK_IMPLEMENTED
+#undef XC_LOCK_UNSUED
+
+#ifdef ZEND_WIN32
+#	define XC_INTERPROCESS_LOCK_IMPLEMENTED
+#	ifndef ZTS
+#		define XC_LOCK_UNSUED
+#	endif
+#endif
+
+#if defined(PTHREADS)
+#	define XC_INTERPROCESS_LOCK_IMPLEMENTED
+#endif
+
+struct _xc_lock_t {
+#ifdef XC_LOCK_UNSUED
+	int dummy;
+#else
+#	ifdef ZTS
+	MUTEX_T tsrm_mutex;
+#	endif
+
+#	ifndef XC_INTERPROCESS_LOCK_IMPLEMENTED
+#		ifdef ZTS
+	zend_bool use_fcntl;
+#		endif
+	xc_fcntl_lock_t fcntl_lock;
+#	endif
+#endif
+};
+
+xc_lock_t *xc_lock_init(const char *pathname, int interprocess) /* {{{ */
+{
+#ifdef XC_LOCK_UNSUED
+	return (xc_lock_t *) 1;
+#else
+#	ifdef ZTS
+	xc_lock_t *lck = malloc(sizeof(xc_lock_t));
+#		if defined(PTHREADS)
+	pthread_mutexattr_t psharedm;
+	pthread_mutexattr_init(&psharedm);
+	pthread_mutexattr_setpshared(&psharedm, PTHREAD_PROCESS_SHARED);
+	lck->tsrm_mutex = (pthread_mutex_t *) malloc(sizeof(pthread_mutex_t));
+	pthread_mutex_init(lck->tsrm_mutex, &psharedm);
+#		else
+	lck->tsrm_mutex = tsrm_mutex_alloc();
+#		endif
+#	endif
+#	ifndef XC_INTERPROCESS_LOCK_IMPLEMENTED
+#		ifdef ZTS
+	lck->use_fcntl = interprocess;
+	if (lck->use_fcntl)
+#		endif
+		xc_fcntl_init(&lck->fcntl_lock, pathname);
+#	endif
+	return lck;
+#endif
+}
+/* }}} */
+void xc_lock_destroy(xc_lock_t *lck) /* {{{ */
+{
+#ifdef XC_LOCK_UNSUED
+	/* do nothing */
+#else
+#	ifdef ZTS
+	tsrm_mutex_free(lck->tsrm_mutex);
+#	endif
+#	ifndef XC_INTERPROCESS_LOCK_IMPLEMENTED
+#		ifdef ZTS
+	if (lck->use_fcntl)
+#		endif
+		xc_fcntl_destroy(&lck->fcntl_lock);
+#	endif
+	free(lck);
+#endif
+}
+/* }}} */
+void xc_lock(xc_lock_t *lck) /* {{{ */
+{
+#ifdef XC_LOCK_UNSUED
+#else
+#	ifdef ZTS
+	if (tsrm_mutex_lock(lck->tsrm_mutex) < 0) {
+		zend_error(E_ERROR, "xc_lock failed errno:%d", errno);
+	}
+#	endif
+#	ifndef XC_INTERPROCESS_LOCK_IMPLEMENTED
+#		ifdef ZTS
+	if (lck->use_fcntl)
+#		endif
+		xc_fcntl_lock(&lck->fcntl_lock);
+#	endif
+#endif
+}
+/* }}} */
+void xc_rdlock(xc_lock_t *lck) /* {{{ */
+{
+#ifdef XC_LOCK_UNSUED
+#else
+#	ifdef ZTS
+	if (tsrm_mutex_lock(lck->tsrm_mutex) < 0) {
+		zend_error(E_ERROR, "xc_rdlock failed errno:%d", errno);
+	}
+#	endif
+#	ifndef XC_INTERPROCESS_LOCK_IMPLEMENTED
+#		ifdef ZTS
+	if (lck->use_fcntl)
+#		endif
+		xc_fcntl_lock(&lck->fcntl_lock);
+#	endif
+#endif
+}
+/* }}} */
+void xc_unlock(xc_lock_t *lck) /* {{{ */
+{
+#ifdef XC_LOCK_UNSUED
+#else
+#	ifndef XC_INTERPROCESS_LOCK_IMPLEMENTED
+#		ifdef ZTS
+	if (lck->use_fcntl)
+#		endif
+		xc_fcntl_unlock(&lck->fcntl_lock);
+#	endif
+#endif
+#	ifdef ZTS
+	if (tsrm_mutex_unlock(lck->tsrm_mutex) < 0) {
+		zend_error(E_ERROR, "xc_unlock failed errno:%d", errno);
+	}
+#	endif
+}
+/* }}} */
Index: /trunk/xcache/xc_lock.h
===================================================================
--- /trunk/xcache/xc_lock.h	(revision 1198)
+++ /trunk/xcache/xc_lock.h	(revision 1199)
@@ -8,13 +8,8 @@
 typedef struct _xc_lock_t xc_lock_t;
 
-xc_lock_t *xc_fcntl_init(const char *pathname);
-void xc_fcntl_destroy(xc_lock_t *lck);
-void xc_fcntl_lock(xc_lock_t *lck);
-void xc_fcntl_unlock(xc_lock_t *lck);
-
-#define xc_lock_init(name)  xc_fcntl_init(name)
-#define xc_lock_destroy(fd) xc_fcntl_destroy(fd)
-#define xc_lock(fd)         xc_fcntl_lock(fd)
-#define xc_unlock(fd)       xc_fcntl_unlock(fd)
+xc_lock_t *xc_lock_init(const char *pathname, int interprocess /* only with ZTS */);
+void xc_lock_destroy(xc_lock_t *lck);
+void xc_lock(xc_lock_t *lck);
+void xc_unlock(xc_lock_t *lck);
 
 #endif /* XC_LOCK_H_1913F3DED68715D7CDA5A055E79FE0FF */
