Skip to content

implement r/w locks to improve performance #16565

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
122 changes: 115 additions & 7 deletions TSRM/TSRM.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ static size_t tsrm_reserved_pos = 0;
static size_t tsrm_reserved_size = 0;

static MUTEX_T tsmm_mutex; /* thread-safe memory manager mutex */
static MUTEX_T tsrm_env_mutex; /* tsrm environ mutex */
static RWLOCK_T tsrm_env_mutex; /* tsrm environ mutex */

/* New thread handlers */
static tsrm_thread_begin_func_t tsrm_new_thread_begin_handler = NULL;
Expand Down Expand Up @@ -156,7 +156,7 @@ TSRM_API bool tsrm_startup(int expected_threads, int expected_resources, int deb
tsrm_reserved_pos = 0;
tsrm_reserved_size = 0;

tsrm_env_mutex = tsrm_mutex_alloc();
tsrm_env_mutex = tsrm_rwlock_alloc();

return 1;
}/*}}}*/
Expand Down Expand Up @@ -212,7 +212,7 @@ TSRM_API void tsrm_shutdown(void)
free(tsrm_tls_table);
free(resource_types_table);
tsrm_mutex_free(tsmm_mutex);
tsrm_mutex_free(tsrm_env_mutex);
tsrm_rwlock_free(tsrm_env_mutex);
TSRM_ERROR((TSRM_ERROR_LEVEL_CORE, "Shutdown TSRM"));
if (tsrm_error_file!=stderr) {
fclose(tsrm_error_file);
Expand All @@ -236,12 +236,20 @@ TSRM_API void tsrm_shutdown(void)

/* {{{ */
/* environ lock api */
TSRM_API void tsrm_env_lock(void) {
tsrm_mutex_lock(tsrm_env_mutex);
TSRM_API void tsrm_env_lock(bool write) {
if (write) {
tsrm_rwlock_wrlock(tsrm_env_mutex);
} else {
tsrm_rwlock_rlock(tsrm_env_mutex);
}
}

TSRM_API void tsrm_env_unlock(void) {
tsrm_mutex_unlock(tsrm_env_mutex);
TSRM_API void tsrm_env_unlock(bool write) {
if (write) {
tsrm_rwlock_wrunlock(tsrm_env_mutex);
} else {
tsrm_rwlock_runlock(tsrm_env_mutex);
}
} /* }}} */

/* enlarge the arrays for the already active threads */
Expand Down Expand Up @@ -648,6 +656,47 @@ TSRM_API void tsrm_mutex_free(MUTEX_T mutexp)
#endif
}/*}}}*/

/* Allocate a read-write lock */
TSRM_API RWLOCK_T tsrm_rwlock_alloc(void)
{/*{{{*/
RWLOCK_T rwlock;
#ifdef TSRM_WIN32
rwlock = malloc(sizeof(SRWLOCK));
if (!rwlock) {
fprintf(stderr, "Failed to allocate SRWLOCK\n");
return NULL;
}
InitializeSRWLock(rwlock);
#else
rwlock = (pthread_rwlock_t *)malloc(sizeof(pthread_rwlock_t));
if (!rwlock) {
fprintf(stderr, "Failed to allocate pthread_rwlock_t\n");
return NULL;
}
pthread_rwlock_init(rwlock, NULL);
#endif
#ifdef THR_DEBUG
printf("Read-Write Lock created thread: %d\n", mythreadid());
#endif
return rwlock;
}/*}}}*/

/* Free a read-write lock */
TSRM_API void tsrm_rwlock_free(RWLOCK_T rwlock)
{/*{{{*/
if (rwlock) {
#ifdef TSRM_WIN32
// No explicit free function for SRWLOCK, but we still free the memory.
free(rwlock);
#else
pthread_rwlock_destroy(rwlock);
free(rwlock);
#endif
}
#ifdef THR_DEBUG
printf("Read-Write Lock freed thread: %d\n", mythreadid());
#endif
}/*}}}*/

/*
Lock a mutex.
Expand All @@ -664,6 +713,65 @@ TSRM_API int tsrm_mutex_lock(MUTEX_T mutexp)
#endif
}/*}}}*/

/*
Lock a mutex for writing.
A return value of 0 indicates success
*/
TSRM_API int tsrm_rwlock_wrlock(RWLOCK_T rwlock)
{/*{{{*/
TSRM_ERROR((TSRM_ERROR_LEVEL_INFO, "Write locked thread: %ld", tsrm_thread_id()));
#ifdef TSRM_WIN32
AcquireSRWLockExclusive(rwlock);
return 0;
#else
return pthread_rwlock_wrlock(rwlock);
#endif
}/*}}}*/

/*
Lock a mutex for reading.
A return value of 0 indicates success
*/
TSRM_API int tsrm_rwlock_rlock(RWLOCK_T rwlock)
{/*{{{*/
TSRM_ERROR((TSRM_ERROR_LEVEL_INFO, "Read locked thread: %ld", tsrm_thread_id()));
#ifdef TSRM_WIN32
AcquireSRWLockShared(rwlock);
return 0;
#else
return pthread_rwlock_rdlock(rwlock);
#endif
}/*}}}*/

/*
Unlock a mutex for reading.
A return value of 0 indicates success
*/
TSRM_API int tsrm_rwlock_runlock(RWLOCK_T rwlock)
{/*{{{*/
TSRM_ERROR((TSRM_ERROR_LEVEL_INFO, "Read unlocked thread: %ld", tsrm_thread_id()));
#ifdef TSRM_WIN32
ReleaseSRWLockShared(rwlock);
return 0;
#else
return pthread_rwlock_unlock(rwlock);
#endif
}/*}}}*/

/*
Unlock a mutex for writing.
A return value of 0 indicates success
*/
TSRM_API int tsrm_rwlock_wrunlock(RWLOCK_T rwlock)
{/*{{{*/
TSRM_ERROR((TSRM_ERROR_LEVEL_INFO, "Write unlocked thread: %ld", tsrm_thread_id()));
#ifdef TSRM_WIN32
ReleaseSRWLockExclusive(rwlock);
return 0;
#else
return pthread_rwlock_unlock(rwlock);
#endif
}/*}}}*/

/*
Unlock a mutex.
Expand Down
16 changes: 12 additions & 4 deletions TSRM/TSRM.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,11 @@ typedef int ts_rsrc_id;
#ifdef TSRM_WIN32
# define THREAD_T DWORD
# define MUTEX_T CRITICAL_SECTION *
# define RWLOCK_T SRWLOCK *
#else
# define THREAD_T pthread_t
# define MUTEX_T pthread_mutex_t *
# define RWLOCK_T pthread_rwlock_t *
#endif

#include <signal.h>
Expand All @@ -84,8 +86,8 @@ TSRM_API bool tsrm_startup(int expected_threads, int expected_resources, int deb
TSRM_API void tsrm_shutdown(void);

/* environ lock API */
TSRM_API void tsrm_env_lock(void);
TSRM_API void tsrm_env_unlock(void);
TSRM_API void tsrm_env_lock(bool write);
TSRM_API void tsrm_env_unlock(bool write);

/* allocates a new thread-safe-resource id */
TSRM_API ts_rsrc_id ts_allocate_id(ts_rsrc_id *rsrc_id, size_t size, ts_allocate_ctor ctor, ts_allocate_dtor dtor);
Expand Down Expand Up @@ -125,8 +127,14 @@ TSRM_API void tsrm_error_set(int level, const char *debug_filename);
TSRM_API THREAD_T tsrm_thread_id(void);
TSRM_API MUTEX_T tsrm_mutex_alloc(void);
TSRM_API void tsrm_mutex_free(MUTEX_T mutexp);
TSRM_API RWLOCK_T tsrm_rwlock_alloc(void);
TSRM_API void tsrm_rwlock_free(RWLOCK_T rwlock);
TSRM_API int tsrm_mutex_lock(MUTEX_T mutexp);
TSRM_API int tsrm_mutex_unlock(MUTEX_T mutexp);
TSRM_API int tsrm_rwlock_wrlock(RWLOCK_T rwlock);
TSRM_API int tsrm_rwlock_wrunlock(RWLOCK_T rwlock);
TSRM_API int tsrm_rwlock_rlock(RWLOCK_T rwlock);
TSRM_API int tsrm_rwlock_runlock(RWLOCK_T rwlock);
#ifdef HAVE_SIGPROCMASK
TSRM_API int tsrm_sigmask(int how, const sigset_t *set, sigset_t *oldset);
#endif
Expand Down Expand Up @@ -188,8 +196,8 @@ TSRM_API bool tsrm_is_managed_thread(void);

#else /* non ZTS */

#define tsrm_env_lock()
#define tsrm_env_unlock()
#define tsrm_env_lock(write)
#define tsrm_env_unlock(write)

#define TSRMG_STATIC(id, type, element)
#define TSRMLS_MAIN_CACHE_EXTERN()
Expand Down
14 changes: 7 additions & 7 deletions ext/standard/basic_functions.c
Original file line number Diff line number Diff line change
Expand Up @@ -448,9 +448,9 @@ PHP_RSHUTDOWN_FUNCTION(basic) /* {{{ */
BG(strtok_string) = NULL;
}
#ifdef HAVE_PUTENV
tsrm_env_lock();
tsrm_env_lock(true);
zend_hash_destroy(&BG(putenv_ht));
tsrm_env_unlock();
tsrm_env_unlock(true);
#endif

if (BG(umask) != -1) {
Expand Down Expand Up @@ -687,7 +687,7 @@ PHPAPI zend_string *php_getenv(const char *str, size_t str_len) {
}
}
#else
tsrm_env_lock();
tsrm_env_lock(false);

/* system method returns a const */
char *ptr = getenv(str);
Expand All @@ -696,7 +696,7 @@ PHPAPI zend_string *php_getenv(const char *str, size_t str_len) {
result = zend_string_init(ptr, strlen(ptr), 0);
}

tsrm_env_unlock();
tsrm_env_unlock(false);
return result;
#endif
}
Expand Down Expand Up @@ -772,7 +772,7 @@ PHP_FUNCTION(putenv)
pe.key = zend_string_init(setting, setting_len, 0);
}

tsrm_env_lock();
tsrm_env_lock(true);
zend_hash_del(&BG(putenv_ht), pe.key);

/* find previous value */
Expand Down Expand Up @@ -807,7 +807,7 @@ PHP_FUNCTION(putenv)
}
/* valw may be NULL, but the failed conversion still needs to be checked. */
if (!keyw || !valw && value) {
tsrm_env_unlock();
tsrm_env_unlock(true);
free(pe.putenv_string);
zend_string_release(pe.key);
free(keyw);
Expand Down Expand Up @@ -835,7 +835,7 @@ PHP_FUNCTION(putenv)
tzset();
}
#endif
tsrm_env_unlock();
tsrm_env_unlock(true);
#ifdef PHP_WIN32
free(keyw);
free(valw);
Expand Down
4 changes: 2 additions & 2 deletions ext/standard/info.c
Original file line number Diff line number Diff line change
Expand Up @@ -968,7 +968,7 @@ PHPAPI ZEND_COLD void php_print_info(int flag)
SECTION("Environment");
php_info_print_table_start();
php_info_print_table_header(2, "Variable", "Value");
tsrm_env_lock();
tsrm_env_lock(false);
for (env=environ; env!=NULL && *env !=NULL; env++) {
tmp1 = estrdup(*env);
if (!(tmp2=strchr(tmp1,'='))) { /* malformed entry? */
Expand All @@ -980,7 +980,7 @@ PHPAPI ZEND_COLD void php_print_info(int flag)
php_info_print_table_row(2, tmp1, tmp2);
efree(tmp1);
}
tsrm_env_unlock();
tsrm_env_unlock(false);
php_info_print_table_end();
}

Expand Down
4 changes: 2 additions & 2 deletions main/php_variables.c
Original file line number Diff line number Diff line change
Expand Up @@ -628,7 +628,7 @@ static zend_always_inline void import_environment_variable(HashTable *ht, char *

static void _php_import_environment_variables(zval *array_ptr)
{
tsrm_env_lock();
tsrm_env_lock(false);

#ifndef PHP_WIN32
for (char **env = environ; env != NULL && *env != NULL; env++) {
Expand All @@ -646,7 +646,7 @@ static void _php_import_environment_variables(zval *array_ptr)
FreeEnvironmentStringsW(environmentw);
#endif

tsrm_env_unlock();
tsrm_env_unlock(false);
}

static void _php_load_environment_variables(zval *array_ptr)
Expand Down
4 changes: 2 additions & 2 deletions sapi/litespeed/lsapi_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ static void litespeed_php_import_environment_variables(zval *array_ptr)
return;
}

tsrm_env_lock();
tsrm_env_lock(false);
for (env = environ; env != NULL && *env != NULL; env++) {
p = strchr(*env, '=');
if (!p) { /* malformed entry? */
Expand All @@ -249,7 +249,7 @@ static void litespeed_php_import_environment_variables(zval *array_ptr)
t[nlen] = '\0';
add_variable(t, nlen, p + 1, strlen( p + 1 ), array_ptr);
}
tsrm_env_unlock();
tsrm_env_unlock(false);
if (t != buf && t != NULL) {
efree(t);
}
Expand Down