summaryrefslogtreecommitdiff
path: root/TSRM/TSRM.c
diff options
context:
space:
mode:
authorBen Mansell <joosters@php.net>2001-03-06 15:07:57 +0000
committerBen Mansell <joosters@php.net>2001-03-06 15:07:57 +0000
commit5d6cb2fc325fa883f9fbf132fe9eb37db3587aa2 (patch)
treebf2b3a52ea81b414eeae35761c8d1331faa6fd7a /TSRM/TSRM.c
parent559c254f8f575e5cdd863314edfd11e783b116a8 (diff)
downloadphp-git-5d6cb2fc325fa883f9fbf132fe9eb37db3587aa2.tar.gz
Speedup for pthread implementation. We make use of thread local storage
to allow access to the current thread's resources without having to obtain the memory mutex and traverse our hash table. This is a big performance win!
Diffstat (limited to 'TSRM/TSRM.c')
-rw-r--r--TSRM/TSRM.c73
1 files changed, 60 insertions, 13 deletions
diff --git a/TSRM/TSRM.c b/TSRM/TSRM.c
index d92d1e7f07..24d8ea969e 100644
--- a/TSRM/TSRM.c
+++ b/TSRM/TSRM.c
@@ -59,6 +59,9 @@ static void (*tsrm_new_thread_end_handler)();
/* Debug support */
int tsrm_error(int level, const char *format, ...);
+
+/* Read a resource from a thread's resource storage */
+void *ts_resource_read( tsrm_tls_entry *thread_resources, ts_rsrc_id id );
static int tsrm_error_level;
static FILE *tsrm_error_file;
#if TSRM_DEBUG
@@ -69,11 +72,19 @@ static FILE *tsrm_error_file;
#define TSRM_SAFE_ARRAY_OFFSET(array, offset, range) array[offset]
#endif
+#if defined(PTHREADS)
+/* Thread local storage */
+static pthread_key_t tls_key;
+#endif
+
+
/* Startup TSRM (call once for the entire process) */
TSRM_API int tsrm_startup(int expected_threads, int expected_resources, int debug_level, char *debug_filename)
{
#if defined(GNUPTH)
pth_init();
+#elif defined(PTHREADS)
+ pthread_key_create( &tls_key, 0 );
#endif
tsrm_error_file = stderr;
@@ -141,6 +152,8 @@ TSRM_API void tsrm_shutdown(void)
}
#if defined(GNUPTH)
pth_kill();
+#elif defined(PTHREADS)
+ pthread_key_delete( tls_key );
#endif
}
@@ -211,7 +224,10 @@ static void allocate_new_resource(tsrm_tls_entry **thread_resources_ptr, THREAD_
(*thread_resources_ptr)->thread_id = thread_id;
(*thread_resources_ptr)->next = NULL;
- tsrm_mutex_unlock(tsmm_mutex);
+#if defined(PTHREADS)
+ /* Set thread local storage to this new thread resources structure */
+ pthread_setspecific( tls_key, (void *)*thread_resources_ptr );
+#endif
if (tsrm_new_thread_begin_handler) {
tsrm_new_thread_begin_handler(thread_id);
@@ -222,6 +238,9 @@ static void allocate_new_resource(tsrm_tls_entry **thread_resources_ptr, THREAD_
resource_types_table[i].ctor((*thread_resources_ptr)->storage[i]);
}
}
+
+ tsrm_mutex_unlock(tsmm_mutex);
+
if (tsrm_new_thread_end_handler) {
tsrm_new_thread_end_handler(thread_id);
}
@@ -234,13 +253,25 @@ TSRM_API void *ts_resource_ex(ts_rsrc_id id, THREAD_T *th_id)
THREAD_T thread_id;
int hash_value;
tsrm_tls_entry *thread_resources;
- void *resource;
- if (th_id) {
- thread_id = *th_id;
- } else {
+ if( !th_id ) {
+#if defined(PTHREADS)
+ /* Fast path for looking up the resources for the current
+ * thread. Its used by just about every call to
+ * ts_resource_ex(). This avoids the need for a mutex lock
+ * and our hashtable lookup.
+ */
+ thread_resources = pthread_getspecific( tls_key );
+ if( thread_resources ) {
+ TSRM_ERROR(TSRM_ERROR_LEVEL_INFO, "Fetching resource id %d for current thread %d", id, (long) thread_resources->thread_id );
+ return ts_resource_read( thread_resources, id );
+ }
+#endif
thread_id = tsrm_thread_id();
- }
+ } else {
+ thread_id = *th_id;
+ }
+
TSRM_ERROR(TSRM_ERROR_LEVEL_INFO, "Fetching resource id %d for thread %ld", id, (long) thread_id);
tsrm_mutex_lock(tsmm_mutex);
@@ -250,7 +281,6 @@ TSRM_API void *ts_resource_ex(ts_rsrc_id id, THREAD_T *th_id)
if (!thread_resources) {
allocate_new_resource(&tsrm_tls_table[hash_value], thread_id);
return ts_resource_ex(id, &thread_id);
- /* thread_resources = tsrm_tls_table[hash_value]; */
} else {
do {
if (thread_resources->thread_id == thread_id) {
@@ -268,15 +298,25 @@ TSRM_API void *ts_resource_ex(ts_rsrc_id id, THREAD_T *th_id)
}
} while (thread_resources);
}
+ tsrm_mutex_unlock(tsmm_mutex);
+ return ts_resource_read( thread_resources, id );
+}
- resource = TSRM_SAFE_ARRAY_OFFSET(thread_resources->storage, TSRM_UNSHUFFLE_RSRC_ID(id), thread_resources->count);
- tsrm_mutex_unlock(tsmm_mutex);
+/* Read a specific resource from the thread's resources.
+ * This is called outside of a mutex, so have to be aware about external
+ * changes to the structure as we read it.
+ */
+void *ts_resource_read( tsrm_tls_entry *thread_resources, ts_rsrc_id id )
+{
+ void *resource;
+ resource = TSRM_SAFE_ARRAY_OFFSET(thread_resources->storage, TSRM_UNSHUFFLE_RSRC_ID(id), thread_resources->count);
if (resource) {
- TSRM_ERROR(TSRM_ERROR_LEVEL_INFO, "Successfully fetched resource id %d for thread id %ld - %x", id, (long) thread_id, (long) resource);
+ TSRM_ERROR(TSRM_ERROR_LEVEL_INFO, "Successfully fetched resource id %d for thread id %ld - %x", id, (long) thread_resources->thread_id, (long) resource);
} else {
TSRM_ERROR(TSRM_ERROR_LEVEL_ERROR, "Resource id %d is out of range (%d..%d)", id, TSRM_SHUFFLE_RSRC_ID(0), TSRM_SHUFFLE_RSRC_ID(thread_resources->count-1));
+ abort();
}
return resource;
}
@@ -285,9 +325,10 @@ TSRM_API void *ts_resource_ex(ts_rsrc_id id, THREAD_T *th_id)
/* frees all resources allocated for the current thread */
void ts_free_thread(void)
{
+ tsrm_tls_entry *thread_resources;
+ int i;
THREAD_T thread_id = tsrm_thread_id();
int hash_value;
- tsrm_tls_entry *thread_resources;
tsrm_tls_entry *last=NULL;
tsrm_mutex_lock(tsmm_mutex);
@@ -296,20 +337,26 @@ void ts_free_thread(void)
while (thread_resources) {
if (thread_resources->thread_id == thread_id) {
- int i;
+ tsrm_mutex_unlock(tsmm_mutex);
for (i=0; i<thread_resources->count; i++) {
if (resource_types_table[i].dtor) {
resource_types_table[i].dtor(thread_resources->storage[i]);
- }
+ }
+ }
+ for (i=0; i<thread_resources->count; i++) {
free(thread_resources->storage[i]);
}
+ tsrm_mutex_lock(tsmm_mutex);
free(thread_resources->storage);
if (last) {
last->next = thread_resources->next;
} else {
tsrm_tls_table[hash_value]=NULL;
}
+#if defined(PTHREADS)
+ pthread_setspecific( tls_key, 0 );
+#endif
free(thread_resources);
break;
}