mirror of
https://github.com/php/php-src.git
synced 2024-09-29 22:06:09 +00:00
4042f543c4
Historicaly, these macros were introduced as a protection from execution timeout handling, but we don't need them anymore after "safe execution timeout" implementation. These macros are still useful to protect from termination during inner process data modification, because of OS signals (e.g. SIGTERM during OPcache SHM update).
253 lines
7.6 KiB
C
253 lines
7.6 KiB
C
/*
|
|
+----------------------------------------------------------------------+
|
|
| Zend Engine |
|
|
+----------------------------------------------------------------------+
|
|
| Copyright (c) 1998-2016 Zend Technologies Ltd. (http://www.zend.com) |
|
|
+----------------------------------------------------------------------+
|
|
| This source file is subject to version 2.00 of the Zend license, |
|
|
| that is bundled with this package in the file LICENSE, and is |
|
|
| available through the world-wide-web at the following url: |
|
|
| http://www.zend.com/license/2_00.txt. |
|
|
| If you did not receive a copy of the Zend license and are unable to |
|
|
| obtain it through the world-wide-web, please send a note to |
|
|
| license@zend.com so we can mail you a copy immediately. |
|
|
+----------------------------------------------------------------------+
|
|
| Authors: Dmitry Stogov <dmitry@zend.com> |
|
|
+----------------------------------------------------------------------+
|
|
*/
|
|
|
|
/* $Id: $ */
|
|
|
|
#include "zend.h"
|
|
#include "zend_globals.h"
|
|
|
|
ZEND_API zend_string *(*zend_new_interned_string)(zend_string *str);
|
|
ZEND_API void (*zend_interned_strings_snapshot)(void);
|
|
ZEND_API void (*zend_interned_strings_restore)(void);
|
|
|
|
static zend_string *zend_new_interned_string_int(zend_string *str);
|
|
static void zend_interned_strings_snapshot_int(void);
|
|
static void zend_interned_strings_restore_int(void);
|
|
|
|
ZEND_API zend_ulong zend_hash_func(const char *str, size_t len)
|
|
{
|
|
return zend_inline_hash_func(str, len);
|
|
}
|
|
|
|
#ifndef ZTS
|
|
static void _str_dtor(zval *zv)
|
|
{
|
|
zend_string *str = Z_STR_P(zv);
|
|
pefree(str, GC_FLAGS(str) & IS_STR_PERSISTENT);
|
|
}
|
|
#endif
|
|
|
|
/* Readonly, so assigned also per thread. */
|
|
static const zend_string **known_interned_strings = NULL;
|
|
static uint32_t known_interned_strings_count = 0;
|
|
|
|
ZEND_API uint32_t zend_intern_known_strings(const char **strings, uint32_t count)
|
|
{
|
|
uint32_t i, old_count = known_interned_strings_count;
|
|
|
|
known_interned_strings = perealloc(known_interned_strings, sizeof(char*) * (old_count + count), 1);
|
|
for (i = 0; i < count; i++) {
|
|
#ifndef ZTS
|
|
zend_string *str = zend_string_init(strings[i], strlen(strings[i]), 1);
|
|
known_interned_strings[known_interned_strings_count + i] =
|
|
zend_new_interned_string_int(str);
|
|
#else
|
|
known_interned_strings[known_interned_strings_count + i] =
|
|
zend_zts_interned_string_init(strings[i], strlen(strings[i]));
|
|
#endif
|
|
}
|
|
known_interned_strings_count = old_count + count;
|
|
return old_count;
|
|
}
|
|
|
|
static const char *known_strings[] = {
|
|
#define _ZEND_STR_DSC(id, str) str,
|
|
ZEND_KNOWN_STRINGS(_ZEND_STR_DSC)
|
|
#undef _ZEND_STR_DSC
|
|
NULL
|
|
};
|
|
|
|
void zend_known_interned_strings_init(zend_string ***strings, uint32_t *count)
|
|
{
|
|
*strings = (zend_string **)known_interned_strings;
|
|
*count = known_interned_strings_count;
|
|
}
|
|
|
|
void zend_interned_strings_init(void)
|
|
{
|
|
#ifndef ZTS
|
|
zend_string *str;
|
|
|
|
zend_hash_init(&CG(interned_strings), 1024, NULL, _str_dtor, 1);
|
|
|
|
CG(interned_strings).nTableMask = -CG(interned_strings).nTableSize;
|
|
HT_SET_DATA_ADDR(&CG(interned_strings), pemalloc(HT_SIZE(&CG(interned_strings)), 1));
|
|
HT_HASH_RESET(&CG(interned_strings));
|
|
CG(interned_strings).u.flags |= HASH_FLAG_INITIALIZED;
|
|
|
|
/* interned empty string */
|
|
str = zend_string_alloc(sizeof("")-1, 1);
|
|
ZSTR_VAL(str)[0] = '\000';
|
|
CG(empty_string) = zend_new_interned_string_int(str);
|
|
#endif
|
|
|
|
/* one char strings (the actual interned strings are going to be created by ext/opcache) */
|
|
memset(CG(one_char_string), 0, sizeof(CG(one_char_string)));
|
|
|
|
/* known strings */
|
|
zend_intern_known_strings(known_strings, (sizeof(known_strings) / sizeof(known_strings[0])) - 1);
|
|
zend_known_interned_strings_init(&CG(known_strings), &CG(known_strings_count));
|
|
|
|
zend_new_interned_string = zend_new_interned_string_int;
|
|
zend_interned_strings_snapshot = zend_interned_strings_snapshot_int;
|
|
zend_interned_strings_restore = zend_interned_strings_restore_int;
|
|
}
|
|
|
|
void zend_interned_strings_dtor(void)
|
|
{
|
|
#ifndef ZTS
|
|
zend_hash_destroy(&CG(interned_strings));
|
|
#else
|
|
uint32_t i;
|
|
|
|
for (i = 0; i < CG(known_strings_count); i++) {
|
|
zend_zts_interned_string_free(&CG(known_strings)[i]);
|
|
}
|
|
#endif
|
|
free(CG(known_strings));
|
|
CG(known_strings) = NULL;
|
|
CG(known_strings_count) = 0;
|
|
known_interned_strings = NULL;
|
|
known_interned_strings_count = 0;
|
|
}
|
|
|
|
static zend_string *zend_new_interned_string_int(zend_string *str)
|
|
{
|
|
#ifndef ZTS
|
|
zend_ulong h;
|
|
uint nIndex;
|
|
uint idx;
|
|
Bucket *p;
|
|
|
|
if (ZSTR_IS_INTERNED(str)) {
|
|
return str;
|
|
}
|
|
|
|
h = zend_string_hash_val(str);
|
|
nIndex = h | CG(interned_strings).nTableMask;
|
|
idx = HT_HASH(&CG(interned_strings), nIndex);
|
|
while (idx != HT_INVALID_IDX) {
|
|
p = HT_HASH_TO_BUCKET(&CG(interned_strings), idx);
|
|
if ((p->h == h) && (ZSTR_LEN(p->key) == ZSTR_LEN(str))) {
|
|
if (!memcmp(ZSTR_VAL(p->key), ZSTR_VAL(str), ZSTR_LEN(str))) {
|
|
zend_string_release(str);
|
|
return p->key;
|
|
}
|
|
}
|
|
idx = Z_NEXT(p->val);
|
|
}
|
|
|
|
GC_REFCOUNT(str) = 1;
|
|
GC_FLAGS(str) |= IS_STR_INTERNED;
|
|
|
|
if (CG(interned_strings).nNumUsed >= CG(interned_strings).nTableSize) {
|
|
if (CG(interned_strings).nTableSize < HT_MAX_SIZE) { /* Let's double the table size */
|
|
void *new_data;
|
|
void *old_data = HT_GET_DATA_ADDR(&CG(interned_strings));
|
|
Bucket *old_buckets = CG(interned_strings).arData;
|
|
|
|
CG(interned_strings).nTableSize += CG(interned_strings).nTableSize;
|
|
CG(interned_strings).nTableMask = -CG(interned_strings).nTableSize;
|
|
new_data = malloc(HT_SIZE(&CG(interned_strings)));
|
|
|
|
if (new_data) {
|
|
HT_SET_DATA_ADDR(&CG(interned_strings), new_data);
|
|
memcpy(CG(interned_strings).arData, old_buckets, sizeof(Bucket) * CG(interned_strings).nNumUsed);
|
|
free(old_data);
|
|
zend_hash_rehash(&CG(interned_strings));
|
|
} else {
|
|
CG(interned_strings).nTableSize = CG(interned_strings).nTableSize >> 1;
|
|
CG(interned_strings).nTableMask = -CG(interned_strings).nTableSize;
|
|
}
|
|
}
|
|
}
|
|
|
|
idx = CG(interned_strings).nNumUsed++;
|
|
CG(interned_strings).nNumOfElements++;
|
|
p = CG(interned_strings).arData + idx;
|
|
p->h = h;
|
|
p->key = str;
|
|
Z_STR(p->val) = str;
|
|
Z_TYPE_INFO(p->val) = IS_INTERNED_STRING_EX;
|
|
nIndex = h | CG(interned_strings).nTableMask;
|
|
Z_NEXT(p->val) = HT_HASH(&CG(interned_strings), nIndex);
|
|
HT_HASH(&CG(interned_strings), nIndex) = HT_IDX_TO_HASH(idx);
|
|
|
|
return str;
|
|
#else
|
|
return str;
|
|
#endif
|
|
}
|
|
|
|
static void zend_interned_strings_snapshot_int(void)
|
|
{
|
|
#ifndef ZTS
|
|
uint idx;
|
|
Bucket *p;
|
|
|
|
idx = CG(interned_strings).nNumUsed;
|
|
while (idx > 0) {
|
|
idx--;
|
|
p = CG(interned_strings).arData + idx;
|
|
ZEND_ASSERT(GC_FLAGS(p->key) & IS_STR_PERSISTENT);
|
|
GC_FLAGS(p->key) |= IS_STR_PERMANENT;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
static void zend_interned_strings_restore_int(void)
|
|
{
|
|
#ifndef ZTS
|
|
uint nIndex;
|
|
uint idx;
|
|
Bucket *p;
|
|
|
|
idx = CG(interned_strings).nNumUsed;
|
|
while (idx > 0) {
|
|
idx--;
|
|
p = CG(interned_strings).arData + idx;
|
|
if (GC_FLAGS(p->key) & IS_STR_PERMANENT) break;
|
|
CG(interned_strings).nNumUsed--;
|
|
CG(interned_strings).nNumOfElements--;
|
|
|
|
GC_FLAGS(p->key) &= ~IS_STR_INTERNED;
|
|
GC_REFCOUNT(p->key) = 1;
|
|
zend_string_free(p->key);
|
|
|
|
nIndex = p->h | CG(interned_strings).nTableMask;
|
|
if (HT_HASH(&CG(interned_strings), nIndex) == HT_IDX_TO_HASH(idx)) {
|
|
HT_HASH(&CG(interned_strings), nIndex) = Z_NEXT(p->val);
|
|
} else {
|
|
uint32_t prev = HT_HASH(&CG(interned_strings), nIndex);
|
|
while (Z_NEXT(HT_HASH_TO_BUCKET(&CG(interned_strings), prev)->val) != idx) {
|
|
prev = Z_NEXT(HT_HASH_TO_BUCKET(&CG(interned_strings), prev)->val);
|
|
}
|
|
Z_NEXT(HT_HASH_TO_BUCKET(&CG(interned_strings), prev)->val) = Z_NEXT(p->val);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
* Local variables:
|
|
* tab-width: 4
|
|
* c-basic-offset: 4
|
|
* indent-tabs-mode: t
|
|
* End:
|
|
*/
|