Permalink
Browse files

first version of atomic branch

use atomic routings in order to reduce the number of WRITE locks
  • Loading branch information...
1 parent 284e45d commit bf1d4007c867d51fb49c66e30edfae4b33082d25 @tony2001 committed Feb 7, 2011
Showing with 228 additions and 35 deletions.
  1. +15 −0 config.m4
  2. +147 −0 ea_atomic.h
  3. +66 −35 eaccelerator.c
View
@@ -99,6 +99,21 @@ dnl Test for union semun
msg=yes,msg=no)
AC_MSG_RESULT([$msg])
+ AC_MSG_CHECKING([if gcc supports __sync_bool_compare_and_swap])
+ AC_TRY_LINK(,
+ [
+ int variable = 1;
+ return (__sync_bool_compare_and_swap(&variable, 1, 2)
+ && __sync_add_and_fetch(&variable, 1)) ? 1 : 0;
+ ],
+ [
+ AC_MSG_RESULT([yes])
+ AC_DEFINE(HAVE_BUILTIN_ATOMIC, 1, [Define to 1 if gcc supports __sync_bool_compare_and_swap() a.o.])
+ ],
+ [
+ AC_MSG_RESULT([no])
+ ])
+
mm_shm_sysvipc=no
mm_shm_mmap_anon=no
mm_shm_mmap_zero=no
View
@@ -0,0 +1,147 @@
+
+/* (c) 2007,2008 Andrei Nigmatulin */
+/* (c) 2009-2011 Jerome Loyet, Antony Dovgal */
+
+#ifndef EA_ATOMIC_H
+#define EA_ATOMIC_H 1
+
+#if HAVE_INTTYPES_H
+# include <inttypes.h>
+#else
+# include <stdint.h>
+#endif
+#include <sched.h>
+
+#ifdef HAVE_BUILTIN_ATOMIC
+
+/**
+ * all the cases below (as provided by upstream) define:
+ * word as atomic_int_t, and
+ * unsigned word as atomic_uint_t
+ * and only use volatile atomic_uint_t as atomic_t
+ */
+
+typedef volatile unsigned long atomic_t;
+# define atomic_fetch_add(value,add) __sync_fetch_and_add(value,add)
+# define atomic_cmp_set(a,b,c) __sync_bool_compare_and_swap(a,b,c)
+
+#elif ( __i386__ || __i386 )
+
+typedef int32_t atomic_int_t;
+typedef uint32_t atomic_uint_t;
+typedef volatile atomic_uint_t atomic_t;
+
+static inline atomic_int_t atomic_fetch_add(atomic_t *value, atomic_int_t add) /* {{{ */
+{
+ __asm__ volatile ( "lock;" "xaddl %0, %1;" :
+ "+r" (add) : "m" (*value) : "memory");
+
+ return add;
+}
+/* }}} */
+
+static inline atomic_uint_t atomic_cmp_set(atomic_t *lock, atomic_uint_t old, atomic_uint_t set) /* {{{ */
+{
+ unsigned char res;
+
+ __asm__ volatile ( "lock;" "cmpxchgl %3, %1;" "sete %0;" :
+ "=a" (res) : "m" (*lock), "a" (old), "r" (set) : "memory");
+
+ return res;
+}
+/* }}} */
+
+#elif ( __amd64__ || __amd64 || __x86_64__ )
+
+typedef int64_t atomic_int_t;
+typedef uint64_t atomic_uint_t;
+typedef volatile atomic_uint_t atomic_t;
+
+static inline atomic_int_t atomic_fetch_add(atomic_t *value, atomic_int_t add) /* {{{ */
+{
+ __asm__ volatile ( "lock;" "xaddq %0, %1;" :
+ "+r" (add) : "m" (*value) : "memory");
+
+ return add;
+}
+/* }}} */
+
+static inline atomic_uint_t atomic_cmp_set(atomic_t *lock, atomic_uint_t old, atomic_uint_t set) /* {{{ */
+{
+ unsigned char res;
+
+ __asm__ volatile ( "lock;" "cmpxchgq %3, %1;" "sete %0;" :
+ "=a" (res) : "m" (*lock), "a" (old), "r" (set) : "memory");
+
+ return res;
+}
+/* }}} */
+
+# if (__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 2))
+
+# elif ( __arm__ || __arm ) /* W-Mark Kubacki */
+
+# if (__arch64__ || __arch64)
+typedef int64_t atomic_int_t;
+typedef uint64_t atomic_uint_t;
+# else
+typedef int32_t atomic_int_t;
+typedef uint32_t atomic_uint_t;
+# endif
+
+# define atomic_cmp_set(a,b,c) __sync_bool_compare_and_swap(a,b,c)
+
+# endif /* defined (__GNUC__) &&... */
+
+#elif ( __sparc__ || __sparc ) /* Marcin Ochab */
+
+# if (__sparcv9 || __sparcv9__)
+
+# if (__arch64__ || __arch64)
+typedef uint64_t atomic_uint_t;
+typedef volatile atomic_uint_t atomic_t;
+
+static inline int atomic_cas_64(atomic_t *lock, atomic_uint_t old, atomic_uint_t new) /* {{{ */
+{
+ __asm__ __volatile__("casx [%2], %3, %0 " : "=&r"(new) : "0"(new), "r"(lock), "r"(old): "memory");
+
+ return new;
+}
+/* }}} */
+
+static inline atomic_uint_t atomic_cmp_set(atomic_t *lock, atomic_uint_t old, atomic_uint_t set) /* {{{ */
+{
+ return (atomic_cas_64(lock, old, set)==old);
+}
+/* }}} */
+# else
+typedef uint32_t atomic_uint_t;
+typedef volatile atomic_uint_t atomic_t;
+
+static inline int atomic_cas_32(atomic_t *lock, atomic_uint_t old, atomic_uint_t new) /* {{{ */
+{
+ __asm__ __volatile__("cas [%2], %3, %0 " : "=&r"(new) : "0"(new), "r"(lock), "r"(old): "memory");
+
+ return new;
+}
+/* }}} */
+
+static inline atomic_uint_t atomic_cmp_set(atomic_t *lock, atomic_uint_t old, atomic_uint_t set) /* {{{ */
+{
+ return (atomic_cas_32(lock, old, set)==old);
+}
+/* }}} */
+# endif
+
+# else /* #if (__sparcv9 || __sparcv9__) */
+# error Sparc v8 and predecessors are not and will not be supported (see bug report 53310)
+# endif /* #if (__sparcv9 || __sparcv9__) */
+
+#else
+
+# error Unsupported processor. Please open a bug report (bugs.php.net).
+
+#endif /* HAVE_BUILTIN_ATOMIC */
+
+#endif /* EA_ATOMIC_H */
+
View
@@ -41,6 +41,7 @@
#include "ea_restore.h"
#include "ea_info.h"
#include "ea_dasm.h"
+#include "ea_atomic.h"
#include <sys/types.h>
#include <sys/stat.h>
@@ -114,64 +115,68 @@ ZEND_DLEXPORT zend_op_array* eaccelerator_compile_file(zend_file_handle *file_ha
/******************************************************************************/
/* Find a script entry with the given hash key */
-static ea_cache_entry* hash_find_mm(const char *key,
- struct stat *buf,
- int *nreloads,
- time_t ttl TSRMLS_DC) {
+static ea_cache_entry* hash_find_mm(const char *key, struct stat *buf, int *nreloads, time_t ttl TSRMLS_DC) /* {{{ */
+{
unsigned int hv, slot;
ea_cache_entry *p, *q;
int key_len = strlen(key);
hv = zend_get_hash_value((char *)key, strlen(key));
slot = hv & EA_HASH_MAX;
- EACCELERATOR_LOCK_RW();
+ EACCELERATOR_LOCK_RD();
q = NULL;
p = ea_mm_instance->hash[slot];
while (p != NULL) {
- if (p->hv == hv && p->realfilename_len == key_len && memcmp(p->realfilename, key, key_len) == 0) {
- if (EAG(check_mtime_enabled) && ea_mm_instance->check_mtime_enabled &&
+ if (p->hv == hv &&
+ p->realfilename_len == key_len &&
+ memcmp(p->realfilename, key, key_len) == 0) {
+ if (p->removed) {
+ continue;
+ }
+
+ if (EAG(check_mtime_enabled) &&
+ ea_mm_instance->check_mtime_enabled &&
(buf->st_mtime != p->mtime || buf->st_size != p->filesize)) {
- /* key is invalid. Remove it. */
- *nreloads = p->nreloads+1;
- if (q == NULL) {
- ea_mm_instance->hash[slot] = p->next;
- } else {
- q->next = p->next;
- }
- ea_mm_instance->hash_cnt--;
- if (p->use_cnt > 0) {
- /* key is used by other process/thread. Schedule it for removal */
- p->removed = 1;
- p->next = ea_mm_instance->removed;
- ea_mm_instance->removed = p;
- ea_mm_instance->rem_cnt++;
- EACCELERATOR_UNLOCK_RW();
- return NULL;
- } else {
- /* key is unused. Remove it. */
- eaccelerator_free_nolock(p);
- EACCELERATOR_UNLOCK_RW();
- return NULL;
- }
+
+ /* the key is invalid, mark it so */
+ *nreloads = p->nreloads + 1;
+ p->removed = 1;
+ atomic_fetch_add(&ea_mm_instance->rem_cnt, 1);
+
+ /* don't touch this, we'll do it on request shutdown
+ if (q == NULL) {
+ ea_mm_instance->hash[slot] = p->next;
+ } else {
+ q->next = p->next;
+ }
+ ea_mm_instance->hash_cnt--;
+ p->next = ea_mm_instance->removed;
+ ea_mm_instance->removed = p;
+ ea_mm_instance->rem_cnt++; */
+
+ EACCELERATOR_UNLOCK_RD();
+ return NULL;
} else {
/* key is valid */
- p->nhits++;
- p->use_cnt++;
+ atomic_fetch_add(&p->nhits, 1);
+ atomic_fetch_add(&p->use_cnt, 1);
p->ttl = ttl;
- EACCELERATOR_UNLOCK_RW();
+ EACCELERATOR_UNLOCK_RD();
return p;
}
}
q = p;
p = p->next;
}
- EACCELERATOR_UNLOCK_RW();
+ EACCELERATOR_UNLOCK_RD();
return NULL;
}
+/* }}} */
/* Add a new entry to the hashtable */
-static void hash_add_mm(ea_cache_entry *x) {
+static void hash_add_mm(ea_cache_entry *x) /* {{{ */
+{
ea_cache_entry *p,*q;
unsigned int slot;
x->hv = zend_get_hash_value(x->realfilename, x->realfilename_len);
@@ -208,6 +213,7 @@ static void hash_add_mm(ea_cache_entry *x) {
}
EACCELERATOR_UNLOCK_RW();
}
+/* }}} */
/* Initialise the shared memory */
static int init_mm(TSRMLS_D) {
@@ -1262,6 +1268,9 @@ PHP_INI_END()
static void eaccelerator_clean_request(TSRMLS_D) {
ea_used_entry *p = (ea_used_entry*)EAG(used_entries);
+ ea_cache_entry *q, *e;
+ int i;
+
if (ea_mm_instance != NULL) {
EACCELERATOR_UNPROTECT();
if (p != NULL) {
@@ -1275,7 +1284,7 @@ static void eaccelerator_clean_request(TSRMLS_D) {
eaccelerator_free_nolock(p->entry);
p->entry = NULL;
} else {
- ea_cache_entry *q = ea_mm_instance->removed;
+ q = ea_mm_instance->removed;
while (q != NULL && q->next != p->entry) {
q = q->next;
}
@@ -1289,6 +1298,28 @@ static void eaccelerator_clean_request(TSRMLS_D) {
}
p = p->next;
}
+
+ /* remove all entries marked as removed */
+ if (ea_mm_instance->rem_cnt > 0) {
+ for (i = 0; i < EA_HASH_SIZE; i++) {
+ e = ea_mm_instance->hash[i];
+ q = NULL;
+ while (e != NULL) {
+ ea_cache_entry *r = e;
+ e = e->next;
+ ea_mm_instance->hash_cnt--;
+ if (r->removed && r->use_cnt <= 0) {
+ if (q != NULL) {
+ q->next = e->next;
+ }
+ eaccelerator_free_nolock (r);
+ ea_mm_instance->rem_cnt--;
+ } else {
+ q = e;
+ }
+ }
+ }
+ }
EACCELERATOR_UNLOCK_RW();
}
EACCELERATOR_PROTECT();

0 comments on commit bf1d400

Please sign in to comment.