diff --git a/TSRM/TSRM.c b/TSRM/TSRM.c index 81136bee4daa9..f4179bc389157 100644 --- a/TSRM/TSRM.c +++ b/TSRM/TSRM.c @@ -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; @@ -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; }/*}}}*/ @@ -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); @@ -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 */ @@ -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. @@ -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. diff --git a/TSRM/TSRM.h b/TSRM/TSRM.h index 80d6cbad04435..6dc53291c0e33 100644 --- a/TSRM/TSRM.h +++ b/TSRM/TSRM.h @@ -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 @@ -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); @@ -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 @@ -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() diff --git a/ext/standard/basic_functions.c b/ext/standard/basic_functions.c index dbbf9896f2b73..0933a866121cc 100644 --- a/ext/standard/basic_functions.c +++ b/ext/standard/basic_functions.c @@ -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) { @@ -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); @@ -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 } @@ -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 */ @@ -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); @@ -835,7 +835,7 @@ PHP_FUNCTION(putenv) tzset(); } #endif - tsrm_env_unlock(); + tsrm_env_unlock(true); #ifdef PHP_WIN32 free(keyw); free(valw); diff --git a/ext/standard/info.c b/ext/standard/info.c index 8a706ef62eb57..50ca43dd93dd0 100644 --- a/ext/standard/info.c +++ b/ext/standard/info.c @@ -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? */ @@ -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(); } diff --git a/main/php_variables.c b/main/php_variables.c index 7569fd43e900c..1110c0e6eb1d6 100644 --- a/main/php_variables.c +++ b/main/php_variables.c @@ -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++) { @@ -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) diff --git a/sapi/litespeed/lsapi_main.c b/sapi/litespeed/lsapi_main.c index 259d4a985cc66..abaa164cdf489 100644 --- a/sapi/litespeed/lsapi_main.c +++ b/sapi/litespeed/lsapi_main.c @@ -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? */ @@ -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); }