package.xml0000664000175000017500000007370714523735540012177 0ustar nikicnikic apcu pecl.php.net APCu - APC User Cache APC User Caching Joe Watkins krakjoe krakjoe@php.net yes Remi Collet remi remi@php.net yes Nikita Popov nikic nikic@php.net yes Anatol Belski ab ab@php.net yes 2023-11-11 5.1.23 5.1.18 stable stable PHP License - Revert use of monotonic clock for TTL (#451) - Fix a crash when serializing packed arrays (e.g. lists) in PHP 8.2+ with `apc.serializer=default`. - Reduce memory usage when serializing packed arrays (e.g. lists) in PHP 8.2+ with `apc.serializer=default`. - Speed up serializing arrays with `apc.serializer=default`. - Reduce memory usage when unserializing instances of the empty array in PHP 7.3+. - Removed no longer working apcue extension. - Increased limit on maximum number of slots. - Made tests compatible with PHP 8.3. 7.0.0-dev 1.10 apcu 2022-09-19 5.1.22 5.1.18 stable stable PHP License - PHP 8.2 compatibility - PHP 8.1 compatibility in apc.php - Fix --enable-apcu-rwlocks configure option - Enable transparent huge pages for mmap memory - Use monotonic clock for TTL 2021-10-07 5.1.21 5.1.18 stable stable PHP License - Fixed compatibility with PHP 8.1 by adding return types to APCUIterator. - APCUIterator::current() and ::key() can no longer be called on an invalid iterator. 2021-03-04 5.1.20 5.1.18 stable stable PHP License - Fix deadlocks when other apcu_* functions are used inside apcu_entry(). It should now be safe to use any functions inside the apcu_entry() callback. - Fix division by zero exception in apc.php. - Fix handling of references in PHP 8 if "default" serializer is used (which is not the default). - Fix string reuse handling if "default" serializer is used (which is not the default). - Check for failures when acquiring read locks to report problems earlier (write locks were already checked previously). - Adjust tests for current PHP 8.1 development branch. - Remove *_api.h headers. Use apc_cache.h instead of apc_cache_api.h etc. 2020-10-05 5.1.19 5.1.18 stable stable PHP License - Fixed apcu_store() with integer keys (#388). - Made apc.use_request_time=0 the default (#391). - Made apcu compatible with PHP 8.0. 2019-10-28 5.1.18 5.1.18 stable stable PHP License - Implement apcu_inc() and apcu_dec() using atomic operations. This means that these functions no longer have to acquire a write lock. These functions will now wraparound on overflow, instead of saturating to a floating point value. - Make table header in apc.php sticky. - Fix compile warnings related to mktemp() usage. - Fix compatibility with PHP 8.0. - Fix required number of arguments for apcu_store() returned by Reflection. 2019-02-08 5.1.17 5.1.15 stable stable PHP License - Fixed compatibility with PHP 7.4 and PHP 8.0. 2018-12-16 5.1.16 5.1.15 stable stable PHP License - Fix build on OSX. 2018-12-07 5.1.15 5.1.15 stable stable PHP License - Restore apc.serializer=php as the default, as the "default" serializer still/again has issues. - Fix possible issues in persistence of arrays with the "default" serializer. - Attempt to reduce shared memory fragmentation. 2018-11-21 5.1.14 5.1.14 stable stable PHP License - Fixed GH #347: Disable slam defense by default. - Fix potential issue with destruction of locks. This does not affect Linux, but might affect Windows and BSD. - Use mutex instead of rwlock for shared memory allocator (if pthreads mutex available). - Require only read-lock for apcu_cas(), by using atomic compare-and-swap. 2018-11-19 5.1.13 5.1.13 stable stable PHP License - Reimplement persistence logic using precise allocation rather than memory pools. This reduces memory usage of cache entries, especially for small values, and improves performance of persisting and unpersisting values. - Fixed GH #335: Stampede protection is broken. - Fixed GH #328: Segfault in apcu_key_info() if APCu is disabled. - Generally make the behavior of functions if APCu is disabled more consistent. - Fixed PHP bug #72980: Empty strings are now consistently allowed as cache keys. - Optimized apcu_key_info() and apcu_cache_info() by using interned strings. - Fix build against PHP master (PHP 7.4). - Many changes to internal C APIs. 2018-07-09 5.1.12 5.1.12 stable stable PHP License - gh#307: Fix 'Timout' sort option (apc.php). - gh#308: Keep search parameter on cache entry detail link (apc.php). - Fix --enable-apcu-clear-signal support. - Show entries with expired global TTL in APCuIterator. - Respect TTL when calculating APCuIterator totals. - The per-entry TTL now always takes precedence over the global TTL. - The global TTL is now always relative to the access time. - apcu_inc() and apcu_dec() no longer update hard-expired entries. Instead a new entry is created. - Added optional $ttl argument to apcu_inc() and apcu_dec(), used when creating a new entry. - PHP bug #76145: Fix use of APCu inside Serializer::(un)serialize(). - gh#304: If apcu_cas() is used on a non-existing entry, don't insert it. - gh#295: Improve APCuIterator performance by using PCRE JIT and preallocating key strings. - Reduce the memory overhead of cache entries. - Prevent potential memory corruption in the cache slam defense implementation. - Ensure cache entry references are released on bailout during unserialization. - Make support for atomic operations a hard requirement for building APCu. - Check write-lock acquisition for failure, to help debugging deadlock situations. - Make sure apcu_inc/dec are atomic when working on a non-existing entry. - Many changes to internal C APIs. 2018-03-08 5.1.11 5.1.11 stable stable PHP License - fix gh#246 apcu_entry hangs - fix gh#259 deadlock in apcu_store - fix gh#281 undefined variable in apc.php - fix handling of fatal errors in apcu_entry - check string lengths when looking up keys - many internal C APIs changed 2018-02-16 5.1.10 5.1.2 stable stable PHP License - fix gh#247 when a NUL char is used as key, apcu_fetch(array) truncates the key - fix gh#248 apcu_fetch may return values causing zend_mm_corruption or segfaults when custom serializer is used - fix gh#260 apcu.serializer=default results in segfault - fix gh#274 non-portable shell == in config.m4 - fix crash when passing bad array to apcu_delete - improve fix gh#266 refcounting errors in APCIterator - fix for PHP 7.3 compatibility 2018-01-02 5.1.9 5.1.2 stable stable PHP License - fix gh#234 mmap disabled when configure is called with --enable-apcu-mmap - fix gh#226 Warning: apcu_fetch(): apc_fetch() expects a string or array of strings. - mitigate gh#223 Fatal error when starting php on windows - add support for PCRE2 in 7.3 - use row formatting for information in phpinfo() tables - set IS_STR_PERSISTENT so refcounting failures are reported by -DRC_DEBUG=1 - fix gh#266 refcounting errors in APCIterator 2017-01-16 5.1.8 5.1.2 stable stable PHP License - fix gh#207 Segmentation fault in apc_sma_api_free() - fix gh#221 memory leak - update to apc dashboard (Tyson Andre) 2016-10-21 5.1.7 5.1.2 stable stable PHP License - fixes gh#19: hung apaches on pthread wrlocks - fixes gh#203: segfaults in bailout / longjmp 2016-10-06 5.1.6 5.1.2 stable stable PHP License - fixes gh#19: Hung apaches on pthread wrlocks - fixes gh#188: Fix Segfault in ZTS build when locking (Tyson Andre) - fixes gh#194: apcu_entry ttl not working - fixes gh#189: SegFault in apc_copy_zval - fixes gh#185: zend_mm_heap corrupted - fixes gh#190: memory leak/failed check for duplicates 2016-06-07 5.1.5 5.1.2 stable stable PHP License - fix version check in control panel page (gh#182, lennartwesdijk) - do not create null strings, palloc may fail 2016-05-12 5.1.4 5.1.2 stable stable PHP License - fix possible memory leak - fix gh#168 drop trying to return strings from shm - fix gh#170 do not create entries when serialization fails 2016-01-15 5.1.3 5.1.2 stable stable PHP License - fixed macro using interlocked increment in Windows - fix gh#158 apc_inc() with negative step value hangs the process - fix gh#164 apc_inc() can take minutes with huge step value 2015-12-02 5.1.2 5.1.2 stable stable PHP License - be wholly consistent with APC in use of atomics 2015-11-20 5.1.0 5.1.0 beta beta PHP License - PHP 7 compatibility - provide APC compatibility in "apc" optional extension - move APCIterator to APC compatibility extension - add APCuIterator without cache argument - drop apcu_bin_* functions - add apcu_entry(key, callback, ttl) function - fix race on refcount of entry when using rwlocks (or on windows) 2014-10-11 4.0.7 4.0.7 beta beta PHP License - fix inconsistent member names for entries in userland 2014-06-12 4.0.6 4.0.6 beta beta PHP License - fix issues with stddef inclusion causing compilation issue 2014-06-11 4.0.5 4.0.5 beta beta PHP License - fix compile with 5.6 beta 2014-03-01 4.0.4 4.0.4 beta beta PHP License - Fix deadlocking due to destroyed locks - Fix various compatibility bugs 2014-01-27 4.0.3 4.0.3 beta beta PHP License - Fix various compatibility problems - Fix a few lingering faults - Remove experimental eval serializer - Fix iterator for compatibility 2013-09-14 4.0.2 4.0.2 beta beta PHP License - Fixed bug #15 APC compatibility option broken (Anatol) - Changes to m4/w32, various (Anatol) - Fix build is always in debug mode, Related to #15 (Anatol) - Fix apc_clear_cache compatibility issues, Issue #18 (Joe) - Fix APCIterator compatibility issues, Issue #20 (Anatol) - Assert cache clear only when 'user' was passed #18 (Anatol) - fix type casts time_t vs ulong (Anatol) - Fixed the gc routine (Anatol) - Restore APC hook for register serializer, Issue #24, #25 (Remi Collet) - Compiler warnings avoided, various (Remi Collet) - Don't segfault if mmap() failed, Issue #27 (Anatol) - Fix variable typo in config.m4 for php_cv_semun (Kevin Abel) - Revert horribleness related to APC_ALIGN (Joe) - Fix call to stream open wrapper (Joe) - php_apcu.dll does not load anymore under X64, Issue #29 (Anatol) - Fix external api functionality (Joe) - Bring back fcntl support for FreeBSD, Issue #36 (Joe) - Bring back spinlocks, various issues (Joe) - Fixed symbol clashing, windows debug mode, again (Anatol) - apcu_key_info / apc_cache_stat functions (Joe) 2013-03-27 4.0.0 4.0.0 beta beta PHP License All opcode caching abilities removed The default locking is now rwlocks APCu API installed in build environment Please see TECHNOTES/README.md apcu-5.1.23/tests/apc_001.phpt0000664000175000017500000000100114523735540014672 0ustar nikicnikic--TEST-- APC: apcu_store/fetch with strings --SKIPIF-- --INI-- apc.enabled=1 apc.enable_cli=1 --FILE-- ===DONE=== --EXPECT-- string(11) "hello world" string(11) "hello world" string(4) "nice" string(11) "hello world" ===DONE=== apcu-5.1.23/tests/apc_002.phpt0000664000175000017500000000074114523735540014705 0ustar nikicnikic--TEST-- APC: apcu_store/fetch with objects --SKIPIF-- --INI-- apc.enabled=1 apc.enable_cli=1 --FILE-- a = true; var_dump($bar); ?> ===DONE=== --EXPECTF-- object(foo)#%d (0) { } object(foo)#%d (0) { } object(foo)#%d (1) { ["a"]=> bool(true) } ===DONE=== apcu-5.1.23/tests/apc_003b.phpt0000664000175000017500000000336114523735540015051 0ustar nikicnikic--TEST-- APC: apcu_store/fetch with objects --SKIPIF-- = 8.1"); ?> --INI-- apc.enabled=1 apc.enable_cli=1 --FILE-- a = true; var_dump($bar); #[AllowDynamicProperties] class bar extends foo { public $pub = 'bar'; protected $pro = 'bar'; private $pri = 'bar'; // we don't see this, we'd need php 5.1 new serialization function __construct() { $this->bar = true; } function change() { $this->pri = 'mod'; } } class baz extends bar { private $pri = 'baz'; function __construct() { parent::__construct(); $this->baz = true; } } $baz = new baz; var_dump($baz); $baz->change(); var_dump($baz); apcu_store('baz', $baz); unset($baz); var_dump(apcu_fetch('baz')); ?> ===DONE=== --EXPECTF-- object(foo)#%d (0) { } object(foo)#%d (0) { } object(foo)#%d (1) { ["a"]=> bool(true) } object(baz)#%d (6) { ["pub"]=> string(3) "bar" ["pro":protected]=> string(3) "bar" ["pri":"bar":private]=> string(3) "bar" ["pri":"baz":private]=> string(3) "baz" ["bar"]=> bool(true) ["baz"]=> bool(true) } object(baz)#%d (6) { ["pub"]=> string(3) "bar" ["pro":protected]=> string(3) "bar" ["pri":"bar":private]=> string(3) "mod" ["pri":"baz":private]=> string(3) "baz" ["bar"]=> bool(true) ["baz"]=> bool(true) } object(baz)#%d (6) { ["pub"]=> string(3) "bar" ["pro":protected]=> string(3) "bar" ["pri":"bar":private]=> string(3) "mod" ["pri":"baz":private]=> string(3) "baz" ["bar"]=> bool(true) ["baz"]=> bool(true) } ===DONE=== apcu-5.1.23/tests/apc_003b_legacy.phpt0000664000175000017500000000327614523735540016402 0ustar nikicnikic--TEST-- APC: apcu_store/fetch with objects --SKIPIF-- = 80100) die("skip For PHP < 8.1"); ?> --INI-- apc.enabled=1 apc.enable_cli=1 --FILE-- a = true; var_dump($bar); class bar extends foo { public $pub = 'bar'; protected $pro = 'bar'; private $pri = 'bar'; // we don't see this, we'd need php 5.1 new serialization function __construct() { $this->bar = true; } function change() { $this->pri = 'mod'; } } class baz extends bar { private $pri = 'baz'; function __construct() { parent::__construct(); $this->baz = true; } } $baz = new baz; var_dump($baz); $baz->change(); var_dump($baz); apcu_store('baz', $baz); unset($baz); var_dump(apcu_fetch('baz')); ?> ===DONE=== --EXPECTF-- object(foo)#%d (0) { } object(foo)#%d (0) { } object(foo)#%d (1) { ["a"]=> bool(true) } object(baz)#%d (6) { ["pri":"baz":private]=> string(3) "baz" ["pub"]=> string(3) "bar" ["pro":protected]=> string(3) "bar" ["pri":"bar":private]=> string(3) "bar" ["bar"]=> bool(true) ["baz"]=> bool(true) } object(baz)#%d (6) { ["pri":"baz":private]=> string(3) "baz" ["pub"]=> string(3) "bar" ["pro":protected]=> string(3) "bar" ["pri":"bar":private]=> string(3) "mod" ["bar"]=> bool(true) ["baz"]=> bool(true) } object(baz)#%d (6) { ["pri":"baz":private]=> string(3) "baz" ["pub"]=> string(3) "bar" ["pro":protected]=> string(3) "bar" ["pri":"bar":private]=> string(3) "mod" ["bar"]=> bool(true) ["baz"]=> bool(true) } ===DONE=== apcu-5.1.23/tests/apc_004.phpt0000664000175000017500000000121614523735540014705 0ustar nikicnikic--TEST-- APC: apcu_store/fetch with bools --SKIPIF-- --INI-- apc.enabled=1 apc.enable_cli=1 --FILE-- ===DONE=== --EXPECT-- bool(false) bool(false) bool(false) bool(true) bool(false) bool(false) bool(false) ===DONE=== apcu-5.1.23/tests/apc_005.phpt0000664000175000017500000000117314523735540014710 0ustar nikicnikic--TEST-- APC: apcu_store/fetch with arrays of objects --SKIPIF-- --INI-- apc.enabled=1 apc.enable_cli=1 --FILE-- ===DONE=== --EXPECT-- array(2) { [0]=> object(stdClass)#1 (0) { } [1]=> object(stdClass)#2 (0) { } } array(2) { [0]=> object(stdClass)#1 (0) { } [1]=> object(stdClass)#2 (0) { } } array(2) { [0]=> object(stdClass)#3 (0) { } [1]=> object(stdClass)#4 (0) { } } ===DONE=== apcu-5.1.23/tests/apc_005b.phpt0000664000175000017500000000130114523735540015043 0ustar nikicnikic--TEST-- APC: apcu_store/fetch with arrays with duplicate object --SKIPIF-- --INI-- apc.enabled=1 apc.enable_cli=1 --FILE-- ===DONE=== --EXPECT-- array(2) { [0]=> object(stdClass)#1 (0) { } [1]=> object(stdClass)#1 (0) { } } array(2) { [0]=> object(stdClass)#1 (0) { } [1]=> object(stdClass)#1 (0) { } } array(2) { [0]=> object(stdClass)#2 (0) { } [1]=> object(stdClass)#2 (0) { } } ===DONE=== apcu-5.1.23/tests/apc_005c.phpt0000664000175000017500000000144014523735540015050 0ustar nikicnikic--TEST-- APC: apcu_store/fetch with arrays with two object references --SKIPIF-- --INI-- apc.enabled=1 apc.enable_cli=1 --FILE-- ===DONE=== --EXPECT-- array(2) { [0]=> &object(stdClass)#1 (0) { } [1]=> &object(stdClass)#1 (0) { } } array(2) { [0]=> &object(stdClass)#1 (0) { } [1]=> &object(stdClass)#1 (0) { } } array(2) { [0]=> &object(stdClass)#2 (0) { } [1]=> &object(stdClass)#2 (0) { } } array(2) { [0]=> &string(3) "roh" [1]=> &string(3) "roh" } ===DONE=== apcu-5.1.23/tests/apc_006.phpt0000664000175000017500000000220014523735540014701 0ustar nikicnikic--TEST-- APC: apcu_store/fetch reference test --SKIPIF-- = 70300) die('skip Only for PHP < 7.3'); ?> --INI-- apc.enabled=1 apc.enable_cli=1 apc.serializer=php report_memleaks=0 --FILE-- ===DONE=== --EXPECT-- array(9) refcount(2){ [0]=> string(1) "a" refcount(1) [1]=> &array(1) refcount(1){ [0]=> string(1) "c" refcount(1) } [2]=> &array(1) refcount(1){ [0]=> string(1) "c" refcount(1) } [3]=> &string(1) "d" refcount(1) [4]=> &string(1) "d" refcount(1) [5]=> &string(1) "d" refcount(1) [6]=> string(1) "e" refcount(1) [7]=> string(1) "e" refcount(1) [8]=> &array(2) refcount(1){ [0]=> string(1) "f" refcount(1) [1]=> &array(2) refcount(1){ [0]=> string(1) "f" refcount(1) [1]=> *RECURSION* } } } ===DONE=== apcu-5.1.23/tests/apc_006_php73.phpt0000664000175000017500000000202214523735540015724 0ustar nikicnikic--TEST-- APC: apcu_store/fetch reference test --SKIPIF-- = 7.3'); if (PHP_VERSION_ID >= 80100) die('skip Only for PHP < 8.1'); ?> --INI-- apc.enabled=1 apc.enable_cli=1 apc.serializer=php report_memleaks=0 --FILE-- ===DONE=== --EXPECTF-- array(9) refcount(2){ [0]=> string(1) "a" %s [1]=> &array(1) refcount(1){ [0]=> string(1) "c" %s } [2]=> &array(1) refcount(1){ [0]=> string(1) "c" %s } [3]=> &string(1) "d" %s [4]=> &string(1) "d" %s [5]=> &string(1) "d" %s [6]=> string(1) "e" %s [7]=> string(1) "e" %s [8]=> &array(2) refcount(1){ [0]=> string(1) "f" %s [1]=> *RECURSION* } } ===DONE=== apcu-5.1.23/tests/apc_006_php81.phpt0000664000175000017500000000240314523735540015726 0ustar nikicnikic--TEST-- APC: apcu_store/fetch reference test --SKIPIF-- = 8.1'); ?> --INI-- apc.enabled=1 apc.enable_cli=1 apc.serializer=php report_memleaks=0 --FILE-- ===DONE=== --EXPECTF-- array(9) refcount(2){ [0]=> string(1) "a" interned [1]=> reference refcount(2) { array(1) refcount(1){ [0]=> string(1) "c" interned } } [2]=> reference refcount(2) { array(1) refcount(1){ [0]=> string(1) "c" interned } } [3]=> reference refcount(3) { string(1) "d" interned } [4]=> reference refcount(3) { string(1) "d" interned } [5]=> reference refcount(3) { string(1) "d" interned } [6]=> string(1) "e" interned [7]=> string(1) "e" interned [8]=> reference refcount(2) { array(2) refcount(1){ [0]=> string(1) "f" interned [1]=> reference refcount(2) { *RECURSION* } } } } ===DONE=== apcu-5.1.23/tests/apc_007.phpt0000664000175000017500000000205714523735540014714 0ustar nikicnikic--TEST-- APC: apcu_inc/apcu_dec test --SKIPIF-- --INI-- apc.enabled=1 apc.enable_cli=1 --FILE-- ===DONE=== --EXPECT-- $foobar = 2 $foobar += 1 = 3 $foobar += 10 = 13 $foobar -= 1 = 12 $foobar -= 10 = 2 $f__bar += 1 = ok $perfection -= 1 = epic fail $foobar += 1 = 3 pass by ref success 1 $foobar -= 1 = 2 pass by ref success 1 ===DONE=== apcu-5.1.23/tests/apc_008.phpt0000664000175000017500000000150614523735540014713 0ustar nikicnikic--TEST-- APC: apcu_cas test --SKIPIF-- --INI-- apc.enabled=1 apc.enable_cli=1 --FILE-- ===DONE=== --EXPECT-- $foobar = 2 $foobar == 1 ? 2 : 1 = fail $foobar == 2 ? 1 : 2 = ok $foobar = 1 $f__bar == 1 ? 2 : 1 = fail $perfection == 2 ? 1 : 2 = epic fail $foobar = 1 ===DONE=== apcu-5.1.23/tests/apc_010.phpt0000664000175000017500000000246214523735540014706 0ustar nikicnikic--TEST-- APC: apcu_store/fetch/add with array of key/value pairs. --SKIPIF-- --INI-- apc.enabled=1 apc.enable_cli=1 --FILE-- ===DONE=== --EXPECT-- array(0) { } array(4) { ["key1"]=> string(6) "value1" ["key2"]=> string(6) "value2" ["key3"]=> array(2) { [0]=> string(7) "value3a" [1]=> string(7) "value3b" } ["key4"]=> int(4) } array(2) { ["key1"]=> string(6) "value1" ["key3"]=> array(2) { [0]=> string(7) "value3a" [1]=> string(7) "value3b" } } array(2) { ["key1"]=> int(-1) ["key3"]=> int(-1) } array(4) { ["key1"]=> string(6) "value1" ["key2"]=> string(6) "value2" ["key3"]=> array(2) { [0]=> string(7) "value3a" [1]=> string(7) "value3b" } ["key4"]=> int(4) } ===DONE=== apcu-5.1.23/tests/apc_011.phpt0000664000175000017500000000057414523735540014711 0ustar nikicnikic--TEST-- APC: apcu_fetch resets array pointers --SKIPIF-- --INI-- apc.enabled=1 apc.enable_cli=1 --FILE-- ===DONE=== --EXPECT-- string(3) "bar" string(3) "bar" ===DONE=== apcu-5.1.23/tests/apc_012.phpt0000664000175000017500000000113614523735540014705 0ustar nikicnikic--TEST-- APC: Atomic inc + dec wrap around on overflow --SKIPIF-- --INI-- apc.enabled=1 apc.enable_cli=1 --FILE-- ===DONE=== --EXPECTF-- int(%i) int(%i) bool(true) bool(true) int(%i) int(%i) bool(true) bool(true) ===DONE=== apcu-5.1.23/tests/apc_013_exists.phpt0000664000175000017500000000062714523735540016311 0ustar nikicnikic--TEST-- APC: apcu_exists --SKIPIF-- --INI-- apc.enabled=1 apc.enable_cli=1 --FILE-- ===DONE=== --EXPECT-- bool(true) bool(false) array(1) { ["testkey"]=> bool(true) } ===DONE=== apcu-5.1.23/tests/apc_014_store_ref.phpt0000664000175000017500000000061014523735540016753 0ustar nikicnikic--TEST-- APC: store array of references --SKIPIF-- --INI-- apc.enabled=1 apc.enable_cli=1 apc.serializer=php --FILE-- 'value1', 'key2' => 'value2', ]; $items = []; foreach($_items as $k => $v) { $items["prefix_$k"] = &$v; } var_dump(apcu_store($items)); ?> ===DONE=== --EXPECT-- array(0) { } ===DONE=== apcu-5.1.23/tests/apc_015.phpt0000664000175000017500000000037714523735540014716 0ustar nikicnikic--TEST-- Copy failure should not create entry --SKIPIF-- --FILE-- --INI-- apc.enabled=1 apc.enable_cli=1 --FILE-- --EXPECT-- bool(true) array(1) { ["foo"]=> string(3) "baz" } NULL array(2) { [0]=> string(3) "foo" [1]=> string(3) "bar" } array(1) { ["foo"]=> string(3) "baz" } NULL apcu-5.1.23/tests/apc_017.phpt0000664000175000017500000000050614523735540014712 0ustar nikicnikic--TEST-- APC should not preserve the IAP --SKIPIF-- --INI-- apc.enabled=1 apc.enable_cli=1 apc.serializer=default --FILE-- --EXPECT-- int(1) apcu-5.1.23/tests/apc_018.phpt0000664000175000017500000000030114523735540014704 0ustar nikicnikic--TEST-- apc_cas() inserts non-existing key with value 0 --INI-- apc.enabled=1 apc.enable_cli=1 --FILE-- --EXPECT-- bool(false) apcu-5.1.23/tests/apc_019.phpt0000664000175000017500000000133414523735540014714 0ustar nikicnikic--TEST-- The per-entry TTL should take precedence over the global TTL --SKIPIF-- --INI-- apc.enabled=1 apc.enable_cli=1 apc.use_request_time=1 apc.ttl=1 --FILE-- --EXPECT-- T+2 bool(false) int(42) T+4 bool(false) bool(false) apcu-5.1.23/tests/apc_020.phpt0000664000175000017500000000144214523735540014704 0ustar nikicnikic--TEST-- Test default expunge logic wrt global and per-entry TTLs --SKIPIF-- --INI-- apc.enabled=1 apc.enable_cli=1 apc.use_request_time=1 apc.ttl=1 apc.shm_size=1M --FILE-- --EXPECT-- bool(false) int(24) int(42) apcu-5.1.23/tests/apc_021.phpt0000664000175000017500000000160714523735540014710 0ustar nikicnikic--TEST-- apcu_inc/dec() should not inc/dec hard expired entries --SKIPIF-- --INI-- apc.enabled=1 apc.enable_cli=1 apc.use_request_time=1 apc.ttl=1 --FILE-- --EXPECT-- T+0: int(1) int(1) int(-1) int(-1) T+2: int(2) int(2) int(-2) int(-2) T+4 int(1) int(1) int(-1) int(-1) apcu-5.1.23/tests/apc_022.phpt0000664000175000017500000000115414523735540014706 0ustar nikicnikic--TEST-- apcu_inc/dec() TTL parameter --SKIPIF-- --INI-- apc.enabled=1 apc.enable_cli=1 apc.use_request_time=1 apc.ttl=0 --FILE-- --EXPECT-- T+0: int(1) int(1) T+1: int(2) int(2) T+2: int(1) int(1) T+3: int(2) int(2) T+4: int(3) int(1) T+5: int(4) int(2) apcu-5.1.23/tests/apc_023.phpt0000664000175000017500000000223414523735540014707 0ustar nikicnikic--TEST-- Serialization edge cases --SKIPIF-- --INI-- apc.enabled=1 apc.enable_cli=1 --FILE-- obj = $obj; $ary = [$obj, $obj2]; apcu_store("key", $ary); // $obj and $obj2->obj should have the same ID var_dump(apcu_fetch("key")); echo "Array next free element:\n"; $ary = [0, 1]; unset($ary[1]); apcu_store("key", $ary); $ary = apcu_fetch("key"); // This should use key 1 rather than 2, as // nextFreeElement should not be preserved (serialization does not) $ary[] = 1; var_dump($ary); echo "Resources:\n"; apcu_store("key", fopen(__FILE__, "r")); ?> --EXPECTF-- GLOBALS: int(1) Object referential identity: array(2) { [0]=> object(stdClass)#3 (0) { } [1]=> object(stdClass)#4 (1) { ["obj"]=> object(stdClass)#3 (0) { } } } Array next free element: array(2) { [0]=> int(0) [1]=> int(1) } Resources: Warning: apcu_store(): Cannot store resources in apcu cache in %s on line %d apcu-5.1.23/tests/apc_024.phpt0000664000175000017500000000050714523735540014711 0ustar nikicnikic--TEST-- Using empty string as key --SKIPIF-- --INI-- apc.enabled=1 apc.enable_cli=1 --FILE-- --EXPECT-- bool(true) bool(true) int(123) bool(true) apcu-5.1.23/tests/apc_025.phpt0000664000175000017500000000064714523735540014717 0ustar nikicnikic--TEST-- APC: apcu_fetch of packed array --SKIPIF-- --INI-- apc.enabled=1 apc.enable_cli=1 --FILE-- --EXPECT-- bool(true) array(8) { [0]=> int(1) [1]=> int(2) [2]=> int(3) [3]=> int(4) [4]=> int(5) [5]=> int(6) [6]=> int(7) [7]=> int(8) } apcu-5.1.23/tests/apc_099.phpt0000664000175000017500000000061714523735540014727 0ustar nikicnikic--TEST-- APCU: apcu_fetch segfault --SKIPIF-- --INI-- apc.enabled=1 apc.enable_cli=1 --FILE-- 'b', 1 => 'c', 2 => 0, ) apcu-5.1.23/tests/apc54_014.phpt0000664000175000017500000000270414523735540015062 0ustar nikicnikic--TEST-- APC: Bug #61742 preload_path does not work due to incorrect string length (variant 1) --SKIPIF-- --CONFLICTS-- server --FILE-- --EXPECT-- bool(true) string(3) "123" bool(true) string(3) "123" bool(true) string(3) "123" bool(true) string(3) "123" bool(true) string(3) "123" bool(true) string(3) "123" bool(true) string(3) "123" bool(true) string(3) "123" bool(true) string(3) "123" bool(true) string(3) "123" bool(true) string(3) "123" bool(true) string(3) "123" bool(true) string(3) "123" bool(true) string(3) "123" bool(true) string(3) "123" bool(true) string(3) "123" bool(true) string(3) "123" bool(true) string(3) "123" bool(true) string(3) "123" bool(true) string(3) "123" bool(true) string(3) "123" bool(true) string(3) "123" bool(true) string(3) "123" bool(true) string(3) "123" bool(true) string(3) "123" bool(true) string(3) "123" bool(true) string(3) "123" bool(true) string(3) "123" bool(true) string(3) "123" bool(true) string(3) "123" done apcu-5.1.23/tests/apc54_018.phpt0000664000175000017500000001034414523735540015065 0ustar nikicnikic--TEST-- APC: Bug #59938 APCIterator fails with large user cache --SKIPIF-- --CONFLICTS-- server --FILE-- getTotalCount()); //returns 10000 var_dump(\$it->current()); //returns false on error FL; $args = array( 'apc.enabled=1', 'apc.enable_cli=1', 'apc.shm_size=64M', ); server_start($file, $args); for ($i = 0; $i < 3; $i++) { run_test_simple(); } echo 'done'; --EXPECTF-- int(10000) array(11) { ["type"]=> string(4) "user" ["key"]=> string(%d) "test-niko-asdfasdfasdfkjasdflkasjdfasf%d" ["value"]=> string(%d) "%s" ["num_hits"]=> int(0) ["mtime"]=> int(%d) ["creation_time"]=> int(%d) ["deletion_time"]=> int(0) ["access_time"]=> int(%d) ["ref_count"]=> int(0) ["mem_size"]=> int(%d) ["ttl"]=> int(0) } int(10000) array(11) { ["type"]=> string(4) "user" ["key"]=> string(%d) "test-niko-asdfasdfasdfkjasdflkasjdfasf%d" ["value"]=> string(%d) "%s" ["num_hits"]=> int(0) ["mtime"]=> int(%d) ["creation_time"]=> int(%d) ["deletion_time"]=> int(0) ["access_time"]=> int(%d) ["ref_count"]=> int(0) ["mem_size"]=> int(%d) ["ttl"]=> int(0) } int(10000) array(11) { ["type"]=> string(4) "user" ["key"]=> string(%d) "test-niko-asdfasdfasdfkjasdflkasjdfasf%d" ["value"]=> string(%d) "%s" ["num_hits"]=> int(0) ["mtime"]=> int(%d) ["creation_time"]=> int(%d) ["deletion_time"]=> int(0) ["access_time"]=> int(%d) ["ref_count"]=> int(0) ["mem_size"]=> int(%d) ["ttl"]=> int(0) } int(10000) array(11) { ["type"]=> string(4) "user" ["key"]=> string(%d) "test-niko-asdfasdfasdfkjasdflkasjdfasf%d" ["value"]=> string(%d) "%s" ["num_hits"]=> int(0) ["mtime"]=> int(%d) ["creation_time"]=> int(%d) ["deletion_time"]=> int(0) ["access_time"]=> int(%d) ["ref_count"]=> int(0) ["mem_size"]=> int(%d) ["ttl"]=> int(0) } int(10000) array(11) { ["type"]=> string(4) "user" ["key"]=> string(%d) "test-niko-asdfasdfasdfkjasdflkasjdfasf%d" ["value"]=> string(%d) "%s" ["num_hits"]=> int(0) ["mtime"]=> int(%d) ["creation_time"]=> int(%d) ["deletion_time"]=> int(0) ["access_time"]=> int(%d) ["ref_count"]=> int(0) ["mem_size"]=> int(%d) ["ttl"]=> int(0) } int(10000) array(11) { ["type"]=> string(4) "user" ["key"]=> string(%d) "test-niko-asdfasdfasdfkjasdflkasjdfasf%d" ["value"]=> string(%d) "%s" ["num_hits"]=> int(0) ["mtime"]=> int(%d) ["creation_time"]=> int(%d) ["deletion_time"]=> int(0) ["access_time"]=> int(%d) ["ref_count"]=> int(0) ["mem_size"]=> int(%d) ["ttl"]=> int(0) } int(10000) array(11) { ["type"]=> string(4) "user" ["key"]=> string(%d) "test-niko-asdfasdfasdfkjasdflkasjdfasf%d" ["value"]=> string(%d) "%s" ["num_hits"]=> int(0) ["mtime"]=> int(%d) ["creation_time"]=> int(%d) ["deletion_time"]=> int(0) ["access_time"]=> int(%d) ["ref_count"]=> int(0) ["mem_size"]=> int(%d) ["ttl"]=> int(0) } int(10000) array(11) { ["type"]=> string(4) "user" ["key"]=> string(%d) "test-niko-asdfasdfasdfkjasdflkasjdfasf%d" ["value"]=> string(%d) "%s" ["num_hits"]=> int(0) ["mtime"]=> int(%d) ["creation_time"]=> int(%d) ["deletion_time"]=> int(0) ["access_time"]=> int(%d) ["ref_count"]=> int(0) ["mem_size"]=> int(%d) ["ttl"]=> int(0) } int(10000) array(11) { ["type"]=> string(4) "user" ["key"]=> string(%d) "test-niko-asdfasdfasdfkjasdflkasjdfasf%d" ["value"]=> string(%d) "%s" ["num_hits"]=> int(0) ["mtime"]=> int(%d) ["creation_time"]=> int(%d) ["deletion_time"]=> int(0) ["access_time"]=> int(%d) ["ref_count"]=> int(0) ["mem_size"]=> int(%d) ["ttl"]=> int(0) } done apcu-5.1.23/tests/apc_disabled.phpt0000664000175000017500000000352114523735540016152 0ustar nikicnikic--TEST-- Behavior of functions when apcu is disabled --INI-- apc.enable_cli=0 --FILE-- "value"])); var_dump(apcu_add(["key" => "value"])); var_dump(apcu_exists(["key"])); var_dump(apcu_fetch(["key"])); var_dump(apcu_delete(["key"])); echo "\ninc/dec/cas\n"; var_dump(apcu_inc("key", 1, $succ_inc)); var_dump($succ_inc); var_dump(apcu_dec("key", 1, $succ_dec)); var_dump($succ_dec); var_dump(apcu_cas("key", 10, 20)); echo "\nentry\n"; var_dump(apcu_entry("key", function() { return 42; })); echo "\niterator\n"; try { new APCUIterator; } catch (Error $e) { echo $e->getMessage(), "\n"; } ?> --EXPECTF-- enabled bool(false) clear_cache bool(true) cache/sma_info Warning: apcu_cache_info(): No APC info available. Perhaps APC is not enabled? Check apc.enabled in your ini file in %s on line %d bool(false) Warning: apcu_sma_info(): No APC SMA info available. Perhaps APC is disabled via apc.enabled? in %s on line %d bool(false) store/add/exists/fetch/key_info/delete bool(false) bool(false) bool(false) bool(false) NULL bool(false) store/add/exists/fetch/delete array array(1) { ["key"]=> int(-1) } array(1) { ["key"]=> int(-1) } array(0) { } array(0) { } array(1) { [0]=> string(3) "key" } inc/dec/cas bool(false) bool(false) bool(false) bool(false) bool(false) entry NULL iterator APC must be enabled to use APCUIterator apcu-5.1.23/tests/apc_entry_001.phpt0000664000175000017500000000101314523735540016116 0ustar nikicnikic--TEST-- APC: apcu_entry (recursion) --SKIPIF-- --INI-- apc.enabled=1 apc.enable_cli=1 --FILE-- ===DONE=== --EXPECT-- string(11) "Hello World" string(11) "Hello World" string(11) "Hello World" ===DONE=== apcu-5.1.23/tests/apc_entry_002.phpt0000664000175000017500000000066214523735540016130 0ustar nikicnikic--TEST-- APC: apcu_entry (exception) --SKIPIF-- --INI-- apc.enabled=1 apc.enable_cli=1 --FILE-- --EXPECTF-- Fatal error: Uncaught Exception: test in %s:3 Stack trace: #0 [internal function]: {closure}('test') #1 %s(%d): apcu_entry('test', Object(Closure)) #2 {main} thrown in %s on line 3 apcu-5.1.23/tests/apc_entry_003.phpt0000664000175000017500000000043414523735540016126 0ustar nikicnikic--TEST-- APC: apcu_entry (fatal error) --SKIPIF-- --INI-- apc.enabled=1 apc.enable_cli=1 --FILE-- --EXPECTF-- Fatal error: %s apcu-5.1.23/tests/apc_entry_recursion.phpt0000664000175000017500000000056614523735540017643 0ustar nikicnikic--TEST-- Recursive apcu_* calls inside apcu_entry() --SKIPIF-- --INI-- apc.enabled=1 apc.enable_cli=1 --FILE-- --EXPECT-- int(124) string(3) "bar" apcu-5.1.23/tests/apcu_fetch_empty_array_reference.phpt0000664000175000017500000000126514523735540022316 0ustar nikicnikic--TEST-- apcu_fetch should work for multiple reference groups --SKIPIF-- --INI-- apc.enabled=1 apc.enable_cli=1 --FILE-- --EXPECT-- array(4) { [0]=> &array(0) { } [1]=> &array(0) { } [2]=> &array(0) { } [3]=> &array(0) { } } array(4) { [0]=> &array(1) { [1]=> object(stdClass)#1 (0) { } } [1]=> &array(1) { [1]=> object(stdClass)#1 (0) { } } [2]=> &array(0) { } [3]=> &array(0) { } } apcu-5.1.23/tests/apc_inc_perf.phpt0000664000175000017500000000104414523735540016166 0ustar nikicnikic--TEST-- APC: apcu_inc/apcu_dec performance test (gh#164) --SKIPIF-- --INI-- apc.enabled=1 apc.enable_cli=1 --FILE-- ===DONE=== --EXPECT-- int(1985229329) int(1) int(1000000000) int(1) bool(true) ===DONE=== apcu-5.1.23/tests/apc_store_array_int_keys.phpt0000664000175000017500000000057614523735540020651 0ustar nikicnikic--TEST-- apcu_store() with int keys in array should convert them to string --SKIPIF-- --INI-- apc.enabled=1 apc.enable_cli=1 --FILE-- "test"])); var_dump(apcu_store(["123" => "test"])); var_dump(apcu_add(["123" => "test"])); ?> --EXPECT-- array(0) { } array(0) { } array(1) { [123]=> int(-1) } apcu-5.1.23/tests/apc_store_array_with_refs.phpt0000664000175000017500000000037614523735540021014 0ustar nikicnikic--TEST-- Store array that references same value twice --INI-- apc.enabled=1 apc.enable_cli=1 apc.serializer=default --FILE-- --EXPECT-- array(2) { [0]=> &NULL [1]=> &NULL } apcu-5.1.23/tests/apc_store_reference.phpt0000664000175000017500000000117314523735540017556 0ustar nikicnikic--TEST-- The outermost value should always be a value, not a reference --INI-- apc.enabled=1 apc.enable_cli=1 apc.serializer=default --SKIPIF-- = 80000) die('skip Requires PHP < 8.0.0'); ?> --FILE-- &$value]); $result = apcu_fetch("key"); var_dump($result); ?> --EXPECT-- array(1) { [0]=> array(1) { [0]=> *RECURSION* } } apcu-5.1.23/tests/apc_store_reference_php8.phpt0000664000175000017500000000113614523735540020514 0ustar nikicnikic--TEST-- The outermost value should always be a value, not a reference --INI-- apc.enabled=1 apc.enable_cli=1 apc.serializer=default --SKIPIF-- = 8.0.0'); ?> --FILE-- &$value]); $result = apcu_fetch("key"); var_dump($result); ?> --EXPECT-- array(1) { [0]=> *RECURSION* } apcu-5.1.23/tests/apc_store_string_reuse.phpt0000664000175000017500000000033114523735540020324 0ustar nikicnikic--TEST-- The same string is used as the cache key and an array key --INI-- apc.enabled=1 apc.enable_cli=1 apc.serializer=default --FILE-- null]; apcu_store($key, $a); ?> --EXPECT-- apcu-5.1.23/tests/apcu_sma_info.phpt0000664000175000017500000000110714523735540016361 0ustar nikicnikic--TEST-- Basic apcu_sma_info() test --INI-- apc.enabled=1 apc.enable_cli=1 apc.shm_segments=1 --FILE-- --EXPECTF-- array(3) { ["num_seg"]=> int(1) ["seg_size"]=> float(%s) ["avail_mem"]=> float(%s) } array(4) { ["num_seg"]=> int(1) ["seg_size"]=> float(%s) ["avail_mem"]=> float(%s) ["block_lists"]=> array(1) { [0]=> array(1) { [0]=> array(2) { ["size"]=> int(%d) ["offset"]=> int(%d) } } } } apcu-5.1.23/tests/bug63224.phpt0000664000175000017500000000726714523735540014751 0ustar nikicnikic--TEST-- APC: Bug #63224 error in __sleep whit reference to other classes --SKIPIF-- --CONFLICTS-- server --FILE-- b->f(); return array('b'); } } class B{ const A_CONSTANT = 1; public \$var; public function f(){ \$this->var = self::A_CONSTANT; } } if(isset(\$_SESSION['lalala'])){ echo "
";
	\$a = \$_SESSION['lalala'];
	print_r(\$a);
} else {
	echo "no session yet, first run\n";
}

//	another file
//	class A and B use autoload
\$b = new B();
\$a = new A();
\$a->b = \$b;

\$_SESSION['lalala'] = \$a;
session_write_close();
FL;

$args = array(
	'apc.enabled=1',
	'apc.cache_by_default=1',
	'apc.enable_cli=1',
    'session.gc_probability=0',
);

server_start($file, $args);

$sid = md5(uniqid("call me maybe", true));
for ($i = 0; $i < 10; $i++) {
	$send = "GET / HTTP/1.1\n" .
			"Host: " . PHP_CLI_SERVER_HOSTNAME . "\n" .
			"Cookie: PHPSESSID=$sid;" .
			"\r\n\r\n";
	for ($j = 0; $j < $num_servers; $j++) {
		run_test(PHP_CLI_SERVER_HOSTNAME, PHP_CLI_SERVER_PORT+$j, $send);
	}
}
echo 'done';
--EXPECT--
no session yet, first run
A Object
(
    [b] => B Object
        (
            [var] => 1
        )

)
A Object
(
    [b] => B Object
        (
            [var] => 1
        )

)
A Object
(
    [b] => B Object
        (
            [var] => 1
        )

)
A Object
(
    [b] => B Object
        (
            [var] => 1
        )

)
A Object
(
    [b] => B Object
        (
            [var] => 1
        )

)
A Object
(
    [b] => B Object
        (
            [var] => 1
        )

)
A Object
(
    [b] => B Object
        (
            [var] => 1
        )

)
A Object
(
    [b] => B Object
        (
            [var] => 1
        )

)
A Object
(
    [b] => B Object
        (
            [var] => 1
        )

)
A Object
(
    [b] => B Object
        (
            [var] => 1
        )

)
A Object
(
    [b] => B Object
        (
            [var] => 1
        )

)
A Object
(
    [b] => B Object
        (
            [var] => 1
        )

)
A Object
(
    [b] => B Object
        (
            [var] => 1
        )

)
A Object
(
    [b] => B Object
        (
            [var] => 1
        )

)
A Object
(
    [b] => B Object
        (
            [var] => 1
        )

)
A Object
(
    [b] => B Object
        (
            [var] => 1
        )

)
A Object
(
    [b] => B Object
        (
            [var] => 1
        )

)
A Object
(
    [b] => B Object
        (
            [var] => 1
        )

)
A Object
(
    [b] => B Object
        (
            [var] => 1
        )

)
A Object
(
    [b] => B Object
        (
            [var] => 1
        )

)
A Object
(
    [b] => B Object
        (
            [var] => 1
        )

)
A Object
(
    [b] => B Object
        (
            [var] => 1
        )

)
A Object
(
    [b] => B Object
        (
            [var] => 1
        )

)
A Object
(
    [b] => B Object
        (
            [var] => 1
        )

)
A Object
(
    [b] => B Object
        (
            [var] => 1
        )

)
A Object
(
    [b] => B Object
        (
            [var] => 1
        )

)
A Object
(
    [b] => B Object
        (
            [var] => 1
        )

)
A Object
(
    [b] => B Object
        (
            [var] => 1
        )

)
A Object
(
    [b] => B Object
        (
            [var] => 1
        )

)
done
apcu-5.1.23/tests/bug76145.phpt0000664000175000017500000000156614523735540014753 0ustar  nikicnikic--TEST--
Bug #76145: Data corruption reading from APCu while unserializing
--INI--
apc.enabled=1
apc.enable_cli=1
error_reporting=E_ALL&~E_DEPRECATED
--FILE--
 session = apcu_fetch('session'); }
  public function serialize() { return ''; }
}

// Create array representing a session associated with a user
// account that is enabled but has not been authenticated.
$session = ['user' => ['enabled' => True], 'authenticated' => False];
$session['user']['authenticated'] = &$session['authenticated'];

apcu_store('session', $session);

// After serializing / deserializing, session checks out as authenticated.
print unserialize(serialize(new Session())) -> session['authenticated'] === True ? 'Authenticated.' : 'Not Authenticated.';

?>
--EXPECT--
Not Authenticated.
apcu-5.1.23/tests/get_included_files_inc1.inc0000664000175000017500000000003414523735540020074 0ustar  nikicnikic
apcu-5.1.23/tests/get_included_files_inc2.inc0000664000175000017500000000012714523735540020100 0ustar  nikicnikic
apcu-5.1.23/tests/get_included_files_inc3.inc0000664000175000017500000000012714523735540020101 0ustar  nikicnikic
apcu-5.1.23/tests/ghbug176.phpt0000664000175000017500000000171514523735540015115 0ustar  nikicnikic--TEST--
APC: GH Bug #176 preload_path segfaults with bad data
--SKIPIF--

--CONFLICTS--
server
--FILE--

--EXPECT--
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
done
apcu-5.1.23/tests/ghbug168.phpt0000664000175000017500000000072514523735540015116 0ustar  nikicnikic--TEST--
gh bug #168
--SKIPIF--

--INI--
apc.enabled=1
apc.enable_cli=1
--FILE--

  string(1) "B"
}
string(1) "A"
array(1) {
  [0]=>
  string(1) "B"
}
string(1) "A"

apcu-5.1.23/tests/ghbug185.phpt0000664000175000017500000000217414523735540015115 0ustar  nikicnikic--TEST--
APC: GH Bug #185 memory corruption
--SKIPIF--

--INI--
apc.enabled=1
apc.enable_cli=1
--FILE--
counterName = $value;
    }

    public function getCounters($name)
    {
        $rex = '/^' . preg_quote($name) . '\./';
        $counters = array();

        foreach (new \APCuIterator($rex) as $counter) {
            $counters[$counter['key']] = $counter['value'];
        }

        return $counters;
    }

    public function add($key, $data, $ttl = 0)
    {
        $ret =  apcu_store($key, $data, $ttl);

        if (true !== $ret) {
            throw new \UnexpectedValueException("apc_store call failed");
        }

        return $ret;
    }
}

$myapc = new MyApc();

var_dump($counterName = uniqid());
var_dump($myapc->setCounterName($counterName));
var_dump($myapc->add($counterName.'.test', 1));
var_dump($results = $myapc->getCounters($counterName));
?>
Done
--EXPECTF--
string(%d) "%s"
NULL
bool(true)
array(1) {
  ["%s.test"]=>
  int(1)
}
Done
apcu-5.1.23/tests/ghbug247.phpt0000664000175000017500000000050414523735540015107 0ustar  nikicnikic--TEST--
GH Bug #247: when a NUL char is used as key, apcu_fetch(array) truncates the key
--SKIPIF--

--INI--
apc.enabled=1
apc.enable_cli=1
--FILE--
 'foo'));
var_dump(apcu_fetch(array("a\0b"))["a\0b"]);
?>
--EXPECT--
string(3) "foo"
apcu-5.1.23/tests/ghbug248.phpt0000664000175000017500000000565114523735540015120 0ustar  nikicnikic--TEST--
GH Bug #248: apcu_fetch may return values causing zend_mm_corruption or segfaults when custom serializer is used
--SKIPIF--

--INI--
apc.enabled=1
apc.enable_cli=1
apc.serializer=default
--FILE--
 2,
        'construct' => ['a'],
        'x1' => 'y',
        'x2' => 'y',
        'x3' => 'y',
        'x4' => 'y',
        'x5' => 'y',
        'x6' => 0,
    ];
}

class MyClass {
    private $_params;

    public function __construct($params) {
        var_dump($params);
        $this->_params = $params;
        var_dump($params);
        $this->_params['ids'] = [4];
        $this->_params['loadValue'] = 'x';
        unset($this->_params['params']);
    }
}

function setup() {
    apcu_delete('mytestkey');
    apcu_store('mytestkey', build_array());
}

function test_apcu_fetch() {
    // Or store second?
    $value = apcu_fetch('mytestkey');
    echo "Fetching the value initially stored into apcu:\n";
    var_dump($value);
    echo "Done dumping initial fetch\n\n";

    new MyClass($value);
    echo "\$value was passed by value, not reference. After instantiating class, the array \$value gets modified\n";
    var_dump($value);

    echo "\nAnd calling apcu_fetch again, the original data is preserved (8 keys, params=2)\n";
    var_dump(apcu_fetch('mytestkey'));
}

setup();
test_apcu_fetch();
?>
--EXPECT--
Fetching the value initially stored into apcu:
array(8) {
  ["params"]=>
  int(2)
  ["construct"]=>
  array(1) {
    [0]=>
    string(1) "a"
  }
  ["x1"]=>
  string(1) "y"
  ["x2"]=>
  string(1) "y"
  ["x3"]=>
  string(1) "y"
  ["x4"]=>
  string(1) "y"
  ["x5"]=>
  string(1) "y"
  ["x6"]=>
  int(0)
}
Done dumping initial fetch

array(8) {
  ["params"]=>
  int(2)
  ["construct"]=>
  array(1) {
    [0]=>
    string(1) "a"
  }
  ["x1"]=>
  string(1) "y"
  ["x2"]=>
  string(1) "y"
  ["x3"]=>
  string(1) "y"
  ["x4"]=>
  string(1) "y"
  ["x5"]=>
  string(1) "y"
  ["x6"]=>
  int(0)
}
array(8) {
  ["params"]=>
  int(2)
  ["construct"]=>
  array(1) {
    [0]=>
    string(1) "a"
  }
  ["x1"]=>
  string(1) "y"
  ["x2"]=>
  string(1) "y"
  ["x3"]=>
  string(1) "y"
  ["x4"]=>
  string(1) "y"
  ["x5"]=>
  string(1) "y"
  ["x6"]=>
  int(0)
}
$value was passed by value, not reference. After instantiating class, the array $value gets modified
array(8) {
  ["params"]=>
  int(2)
  ["construct"]=>
  array(1) {
    [0]=>
    string(1) "a"
  }
  ["x1"]=>
  string(1) "y"
  ["x2"]=>
  string(1) "y"
  ["x3"]=>
  string(1) "y"
  ["x4"]=>
  string(1) "y"
  ["x5"]=>
  string(1) "y"
  ["x6"]=>
  int(0)
}

And calling apcu_fetch again, the original data is preserved (8 keys, params=2)
array(8) {
  ["params"]=>
  int(2)
  ["construct"]=>
  array(1) {
    [0]=>
    string(1) "a"
  }
  ["x1"]=>
  string(1) "y"
  ["x2"]=>
  string(1) "y"
  ["x3"]=>
  string(1) "y"
  ["x4"]=>
  string(1) "y"
  ["x5"]=>
  string(1) "y"
  ["x6"]=>
  int(0)
}
apcu-5.1.23/tests/ghbug335-fail.phpt0000664000175000017500000000125014523735540016015 0ustar  nikicnikic--TEST--
GH Bug #335: APCu stampede protection is broken
--SKIPIF--

--INI--
apc.enabled=1
apc.enable_cli=1
apc.use_request_time=1
apc.slam_defense=0
--FILE--

--EXPECT--
Stampede protection doesn't work
apcu-5.1.23/tests/ghbug335.phpt0000664000175000017500000000124114523735540015104 0ustar  nikicnikic--TEST--
GH Bug #335: APCu stampede protection is broken
--SKIPIF--

--INI--
apc.enabled=1
apc.enable_cli=1
apc.use_request_time=1
apc.slam_defense=1
--FILE--

--EXPECT--
Stampede protection works
apcu-5.1.23/tests/iterator_001.phpt0000664000175000017500000000335114523735540015772 0ustar  nikicnikic--TEST--
APC: APCIterator general
--SKIPIF--

--INI--
apc.enabled=1
apc.enable_cli=1
--FILE--
$value) {
  $keys[$key] = $value['key'];
}
ksort($keys);
var_dump($keys);
?>
===DONE===
--EXPECT--
array(41) {
  ["key0"]=>
  string(4) "key0"
  ["key1"]=>
  string(4) "key1"
  ["key10"]=>
  string(5) "key10"
  ["key11"]=>
  string(5) "key11"
  ["key12"]=>
  string(5) "key12"
  ["key13"]=>
  string(5) "key13"
  ["key14"]=>
  string(5) "key14"
  ["key15"]=>
  string(5) "key15"
  ["key16"]=>
  string(5) "key16"
  ["key17"]=>
  string(5) "key17"
  ["key18"]=>
  string(5) "key18"
  ["key19"]=>
  string(5) "key19"
  ["key2"]=>
  string(4) "key2"
  ["key20"]=>
  string(5) "key20"
  ["key21"]=>
  string(5) "key21"
  ["key22"]=>
  string(5) "key22"
  ["key23"]=>
  string(5) "key23"
  ["key24"]=>
  string(5) "key24"
  ["key25"]=>
  string(5) "key25"
  ["key26"]=>
  string(5) "key26"
  ["key27"]=>
  string(5) "key27"
  ["key28"]=>
  string(5) "key28"
  ["key29"]=>
  string(5) "key29"
  ["key3"]=>
  string(4) "key3"
  ["key30"]=>
  string(5) "key30"
  ["key31"]=>
  string(5) "key31"
  ["key32"]=>
  string(5) "key32"
  ["key33"]=>
  string(5) "key33"
  ["key34"]=>
  string(5) "key34"
  ["key35"]=>
  string(5) "key35"
  ["key36"]=>
  string(5) "key36"
  ["key37"]=>
  string(5) "key37"
  ["key38"]=>
  string(5) "key38"
  ["key39"]=>
  string(5) "key39"
  ["key4"]=>
  string(4) "key4"
  ["key40"]=>
  string(5) "key40"
  ["key5"]=>
  string(4) "key5"
  ["key6"]=>
  string(4) "key6"
  ["key7"]=>
  string(4) "key7"
  ["key8"]=>
  string(4) "key8"
  ["key9"]=>
  string(4) "key9"
}
===DONE===
apcu-5.1.23/tests/iterator_002.phpt0000664000175000017500000000103514523735540015770 0ustar  nikicnikic--TEST--
APC: APCIterator regex
--SKIPIF--

--INI--
apc.enabled=1
apc.enable_cli=1
--FILE--
$value) {
  $vals[$key] = $value['key'];
}
ksort($vals);
var_dump($vals);

?>
===DONE===
--EXPECT--
array(4) {
  ["key10"]=>
  string(5) "key10"
  ["key20"]=>
  string(5) "key20"
  ["key30"]=>
  string(5) "key30"
  ["key40"]=>
  string(5) "key40"
}
===DONE===
apcu-5.1.23/tests/iterator_003.phpt0000664000175000017500000000340214523735540015771 0ustar  nikicnikic--TEST--
APC: APCIterator chunk size
--SKIPIF--

--INI--
apc.enabled=1
apc.enable_cli=1
--FILE--
$value) {
  $vals[$key] = $value['key'];
}
ksort($vals);
var_dump($vals);

?>
===DONE===
--EXPECT--
array(41) {
  ["key0"]=>
  string(4) "key0"
  ["key1"]=>
  string(4) "key1"
  ["key10"]=>
  string(5) "key10"
  ["key11"]=>
  string(5) "key11"
  ["key12"]=>
  string(5) "key12"
  ["key13"]=>
  string(5) "key13"
  ["key14"]=>
  string(5) "key14"
  ["key15"]=>
  string(5) "key15"
  ["key16"]=>
  string(5) "key16"
  ["key17"]=>
  string(5) "key17"
  ["key18"]=>
  string(5) "key18"
  ["key19"]=>
  string(5) "key19"
  ["key2"]=>
  string(4) "key2"
  ["key20"]=>
  string(5) "key20"
  ["key21"]=>
  string(5) "key21"
  ["key22"]=>
  string(5) "key22"
  ["key23"]=>
  string(5) "key23"
  ["key24"]=>
  string(5) "key24"
  ["key25"]=>
  string(5) "key25"
  ["key26"]=>
  string(5) "key26"
  ["key27"]=>
  string(5) "key27"
  ["key28"]=>
  string(5) "key28"
  ["key29"]=>
  string(5) "key29"
  ["key3"]=>
  string(4) "key3"
  ["key30"]=>
  string(5) "key30"
  ["key31"]=>
  string(5) "key31"
  ["key32"]=>
  string(5) "key32"
  ["key33"]=>
  string(5) "key33"
  ["key34"]=>
  string(5) "key34"
  ["key35"]=>
  string(5) "key35"
  ["key36"]=>
  string(5) "key36"
  ["key37"]=>
  string(5) "key37"
  ["key38"]=>
  string(5) "key38"
  ["key39"]=>
  string(5) "key39"
  ["key4"]=>
  string(4) "key4"
  ["key40"]=>
  string(5) "key40"
  ["key5"]=>
  string(4) "key5"
  ["key6"]=>
  string(4) "key6"
  ["key7"]=>
  string(4) "key7"
  ["key8"]=>
  string(4) "key8"
  ["key9"]=>
  string(4) "key9"
}
===DONE===
apcu-5.1.23/tests/iterator_004.phpt0000664000175000017500000000112214523735540015767 0ustar  nikicnikic--TEST--
APC: APCIterator regex & chunk size & list
--SKIPIF--

--INI--
apc.enabled=1
apc.enable_cli=1
--FILE--
$value) {
  $vals[$key] = $value['key'];
}
ksort($vals);
var_dump($vals);

?>
===DONE===
--EXPECT--
array(4) {
  ["key10"]=>
  string(5) "key10"
  ["key20"]=>
  string(5) "key20"
  ["key30"]=>
  string(5) "key30"
  ["key40"]=>
  string(5) "key40"
}
===DONE===
apcu-5.1.23/tests/iterator_005.phpt0000664000175000017500000000343614523735540016002 0ustar  nikicnikic--TEST--
APC: APCIterator delete
--SKIPIF--

--INI--
apc.enabled=1
apc.enable_cli=1
--FILE--
$value) {
  $vals[$key] = $value['key'];
}
foreach($it2 as $key=>$value) {
  $vals2[$key] = $value['key'];
}
ksort($vals2);
var_dump($vals);
var_dump($vals2);

?>
===DONE===
--EXPECT--
array(0) {
}
array(37) {
  ["key0"]=>
  string(4) "key0"
  ["key1"]=>
  string(4) "key1"
  ["key11"]=>
  string(5) "key11"
  ["key12"]=>
  string(5) "key12"
  ["key13"]=>
  string(5) "key13"
  ["key14"]=>
  string(5) "key14"
  ["key15"]=>
  string(5) "key15"
  ["key16"]=>
  string(5) "key16"
  ["key17"]=>
  string(5) "key17"
  ["key18"]=>
  string(5) "key18"
  ["key19"]=>
  string(5) "key19"
  ["key2"]=>
  string(4) "key2"
  ["key21"]=>
  string(5) "key21"
  ["key22"]=>
  string(5) "key22"
  ["key23"]=>
  string(5) "key23"
  ["key24"]=>
  string(5) "key24"
  ["key25"]=>
  string(5) "key25"
  ["key26"]=>
  string(5) "key26"
  ["key27"]=>
  string(5) "key27"
  ["key28"]=>
  string(5) "key28"
  ["key29"]=>
  string(5) "key29"
  ["key3"]=>
  string(4) "key3"
  ["key31"]=>
  string(5) "key31"
  ["key32"]=>
  string(5) "key32"
  ["key33"]=>
  string(5) "key33"
  ["key34"]=>
  string(5) "key34"
  ["key35"]=>
  string(5) "key35"
  ["key36"]=>
  string(5) "key36"
  ["key37"]=>
  string(5) "key37"
  ["key38"]=>
  string(5) "key38"
  ["key39"]=>
  string(5) "key39"
  ["key4"]=>
  string(4) "key4"
  ["key5"]=>
  string(4) "key5"
  ["key6"]=>
  string(4) "key6"
  ["key7"]=>
  string(4) "key7"
  ["key8"]=>
  string(4) "key8"
  ["key9"]=>
  string(4) "key9"
}
===DONE===
apcu-5.1.23/tests/iterator_006.phpt0000664000175000017500000004103114523735540015774 0ustar  nikicnikic--TEST--
APC: APCIterator formats 
--SKIPIF--

--INI--
apc.enabled=1
apc.enable_cli=1
apc.user_entries_hint=4096
--FILE--
 $format) {
	$it_array[$idx] = new APCuIterator(NULL, $format);
}

for($i = 0; $i < 11; $i++) {
  apcu_store("key$i", "value$i");
}

foreach ($it_array as $idx => $it) {
  print_it($it, $idx);
}

function print_it($it, $idx) {
  echo "IT #$idx\n";
  echo "============================\n";
  foreach ($it as $key=>$value) {
    var_dump($key);
    var_dump($value);
  }
  echo "============================\n\n";
}

?>
===DONE===
--EXPECTF--
IT #0
============================
string(4) "key0"
array(1) {
  ["key"]=>
  string(4) "key0"
}
string(4) "key1"
array(1) {
  ["key"]=>
  string(4) "key1"
}
string(4) "key2"
array(1) {
  ["key"]=>
  string(4) "key2"
}
string(4) "key3"
array(1) {
  ["key"]=>
  string(4) "key3"
}
string(4) "key4"
array(1) {
  ["key"]=>
  string(4) "key4"
}
string(4) "key5"
array(1) {
  ["key"]=>
  string(4) "key5"
}
string(4) "key6"
array(1) {
  ["key"]=>
  string(4) "key6"
}
string(4) "key7"
array(1) {
  ["key"]=>
  string(4) "key7"
}
string(4) "key8"
array(1) {
  ["key"]=>
  string(4) "key8"
}
string(4) "key9"
array(1) {
  ["key"]=>
  string(4) "key9"
}
string(5) "key10"
array(1) {
  ["key"]=>
  string(5) "key10"
}
============================

IT #1
============================
string(4) "key0"
array(1) {
  ["value"]=>
  string(6) "value0"
}
string(4) "key1"
array(1) {
  ["value"]=>
  string(6) "value1"
}
string(4) "key2"
array(1) {
  ["value"]=>
  string(6) "value2"
}
string(4) "key3"
array(1) {
  ["value"]=>
  string(6) "value3"
}
string(4) "key4"
array(1) {
  ["value"]=>
  string(6) "value4"
}
string(4) "key5"
array(1) {
  ["value"]=>
  string(6) "value5"
}
string(4) "key6"
array(1) {
  ["value"]=>
  string(6) "value6"
}
string(4) "key7"
array(1) {
  ["value"]=>
  string(6) "value7"
}
string(4) "key8"
array(1) {
  ["value"]=>
  string(6) "value8"
}
string(4) "key9"
array(1) {
  ["value"]=>
  string(6) "value9"
}
string(5) "key10"
array(1) {
  ["value"]=>
  string(7) "value10"
}
============================

IT #2
============================
string(4) "key0"
array(1) {
  ["num_hits"]=>
  int(0)
}
string(4) "key1"
array(1) {
  ["num_hits"]=>
  int(0)
}
string(4) "key2"
array(1) {
  ["num_hits"]=>
  int(0)
}
string(4) "key3"
array(1) {
  ["num_hits"]=>
  int(0)
}
string(4) "key4"
array(1) {
  ["num_hits"]=>
  int(0)
}
string(4) "key5"
array(1) {
  ["num_hits"]=>
  int(0)
}
string(4) "key6"
array(1) {
  ["num_hits"]=>
  int(0)
}
string(4) "key7"
array(1) {
  ["num_hits"]=>
  int(0)
}
string(4) "key8"
array(1) {
  ["num_hits"]=>
  int(0)
}
string(4) "key9"
array(1) {
  ["num_hits"]=>
  int(0)
}
string(5) "key10"
array(1) {
  ["num_hits"]=>
  int(0)
}
============================

IT #3
============================
string(4) "key0"
array(1) {
  ["mtime"]=>
  int(%d)
}
string(4) "key1"
array(1) {
  ["mtime"]=>
  int(%d)
}
string(4) "key2"
array(1) {
  ["mtime"]=>
  int(%d)
}
string(4) "key3"
array(1) {
  ["mtime"]=>
  int(%d)
}
string(4) "key4"
array(1) {
  ["mtime"]=>
  int(%d)
}
string(4) "key5"
array(1) {
  ["mtime"]=>
  int(%d)
}
string(4) "key6"
array(1) {
  ["mtime"]=>
  int(%d)
}
string(4) "key7"
array(1) {
  ["mtime"]=>
  int(%d)
}
string(4) "key8"
array(1) {
  ["mtime"]=>
  int(%d)
}
string(4) "key9"
array(1) {
  ["mtime"]=>
  int(%d)
}
string(5) "key10"
array(1) {
  ["mtime"]=>
  int(%d)
}
============================

IT #4
============================
string(4) "key0"
array(1) {
  ["creation_time"]=>
  int(%d)
}
string(4) "key1"
array(1) {
  ["creation_time"]=>
  int(%d)
}
string(4) "key2"
array(1) {
  ["creation_time"]=>
  int(%d)
}
string(4) "key3"
array(1) {
  ["creation_time"]=>
  int(%d)
}
string(4) "key4"
array(1) {
  ["creation_time"]=>
  int(%d)
}
string(4) "key5"
array(1) {
  ["creation_time"]=>
  int(%d)
}
string(4) "key6"
array(1) {
  ["creation_time"]=>
  int(%d)
}
string(4) "key7"
array(1) {
  ["creation_time"]=>
  int(%d)
}
string(4) "key8"
array(1) {
  ["creation_time"]=>
  int(%d)
}
string(4) "key9"
array(1) {
  ["creation_time"]=>
  int(%d)
}
string(5) "key10"
array(1) {
  ["creation_time"]=>
  int(%d)
}
============================

IT #5
============================
string(4) "key0"
array(1) {
  ["deletion_time"]=>
  int(0)
}
string(4) "key1"
array(1) {
  ["deletion_time"]=>
  int(0)
}
string(4) "key2"
array(1) {
  ["deletion_time"]=>
  int(0)
}
string(4) "key3"
array(1) {
  ["deletion_time"]=>
  int(0)
}
string(4) "key4"
array(1) {
  ["deletion_time"]=>
  int(0)
}
string(4) "key5"
array(1) {
  ["deletion_time"]=>
  int(0)
}
string(4) "key6"
array(1) {
  ["deletion_time"]=>
  int(0)
}
string(4) "key7"
array(1) {
  ["deletion_time"]=>
  int(0)
}
string(4) "key8"
array(1) {
  ["deletion_time"]=>
  int(0)
}
string(4) "key9"
array(1) {
  ["deletion_time"]=>
  int(0)
}
string(5) "key10"
array(1) {
  ["deletion_time"]=>
  int(0)
}
============================

IT #6
============================
string(4) "key0"
array(1) {
  ["access_time"]=>
  int(%d)
}
string(4) "key1"
array(1) {
  ["access_time"]=>
  int(%d)
}
string(4) "key2"
array(1) {
  ["access_time"]=>
  int(%d)
}
string(4) "key3"
array(1) {
  ["access_time"]=>
  int(%d)
}
string(4) "key4"
array(1) {
  ["access_time"]=>
  int(%d)
}
string(4) "key5"
array(1) {
  ["access_time"]=>
  int(%d)
}
string(4) "key6"
array(1) {
  ["access_time"]=>
  int(%d)
}
string(4) "key7"
array(1) {
  ["access_time"]=>
  int(%d)
}
string(4) "key8"
array(1) {
  ["access_time"]=>
  int(%d)
}
string(4) "key9"
array(1) {
  ["access_time"]=>
  int(%d)
}
string(5) "key10"
array(1) {
  ["access_time"]=>
  int(%d)
}
============================

IT #7
============================
string(4) "key0"
array(1) {
  ["ref_count"]=>
  int(0)
}
string(4) "key1"
array(1) {
  ["ref_count"]=>
  int(0)
}
string(4) "key2"
array(1) {
  ["ref_count"]=>
  int(0)
}
string(4) "key3"
array(1) {
  ["ref_count"]=>
  int(0)
}
string(4) "key4"
array(1) {
  ["ref_count"]=>
  int(0)
}
string(4) "key5"
array(1) {
  ["ref_count"]=>
  int(0)
}
string(4) "key6"
array(1) {
  ["ref_count"]=>
  int(0)
}
string(4) "key7"
array(1) {
  ["ref_count"]=>
  int(0)
}
string(4) "key8"
array(1) {
  ["ref_count"]=>
  int(0)
}
string(4) "key9"
array(1) {
  ["ref_count"]=>
  int(0)
}
string(5) "key10"
array(1) {
  ["ref_count"]=>
  int(0)
}
============================

IT #8
============================
string(4) "key0"
array(1) {
  ["mem_size"]=>
  int(%d)
}
string(4) "key1"
array(1) {
  ["mem_size"]=>
  int(%d)
}
string(4) "key2"
array(1) {
  ["mem_size"]=>
  int(%d)
}
string(4) "key3"
array(1) {
  ["mem_size"]=>
  int(%d)
}
string(4) "key4"
array(1) {
  ["mem_size"]=>
  int(%d)
}
string(4) "key5"
array(1) {
  ["mem_size"]=>
  int(%d)
}
string(4) "key6"
array(1) {
  ["mem_size"]=>
  int(%d)
}
string(4) "key7"
array(1) {
  ["mem_size"]=>
  int(%d)
}
string(4) "key8"
array(1) {
  ["mem_size"]=>
  int(%d)
}
string(4) "key9"
array(1) {
  ["mem_size"]=>
  int(%d)
}
string(5) "key10"
array(1) {
  ["mem_size"]=>
  int(%d)
}
============================

IT #9
============================
string(4) "key0"
array(1) {
  ["ttl"]=>
  int(0)
}
string(4) "key1"
array(1) {
  ["ttl"]=>
  int(0)
}
string(4) "key2"
array(1) {
  ["ttl"]=>
  int(0)
}
string(4) "key3"
array(1) {
  ["ttl"]=>
  int(0)
}
string(4) "key4"
array(1) {
  ["ttl"]=>
  int(0)
}
string(4) "key5"
array(1) {
  ["ttl"]=>
  int(0)
}
string(4) "key6"
array(1) {
  ["ttl"]=>
  int(0)
}
string(4) "key7"
array(1) {
  ["ttl"]=>
  int(0)
}
string(4) "key8"
array(1) {
  ["ttl"]=>
  int(0)
}
string(4) "key9"
array(1) {
  ["ttl"]=>
  int(0)
}
string(5) "key10"
array(1) {
  ["ttl"]=>
  int(0)
}
============================

IT #10
============================
string(4) "key0"
array(0) {
}
string(4) "key1"
array(0) {
}
string(4) "key2"
array(0) {
}
string(4) "key3"
array(0) {
}
string(4) "key4"
array(0) {
}
string(4) "key5"
array(0) {
}
string(4) "key6"
array(0) {
}
string(4) "key7"
array(0) {
}
string(4) "key8"
array(0) {
}
string(4) "key9"
array(0) {
}
string(5) "key10"
array(0) {
}
============================

IT #11
============================
string(4) "key0"
array(10) {
  ["key"]=>
  string(4) "key0"
  ["value"]=>
  string(6) "value0"
  ["num_hits"]=>
  int(0)
  ["mtime"]=>
  int(%d)
  ["creation_time"]=>
  int(%d)
  ["deletion_time"]=>
  int(0)
  ["access_time"]=>
  int(%d)
  ["ref_count"]=>
  int(0)
  ["mem_size"]=>
  int(%d)
  ["ttl"]=>
  int(0)
}
string(4) "key1"
array(10) {
  ["key"]=>
  string(4) "key1"
  ["value"]=>
  string(6) "value1"
  ["num_hits"]=>
  int(0)
  ["mtime"]=>
  int(%d)
  ["creation_time"]=>
  int(%d)
  ["deletion_time"]=>
  int(0)
  ["access_time"]=>
  int(%d)
  ["ref_count"]=>
  int(0)
  ["mem_size"]=>
  int(%d)
  ["ttl"]=>
  int(0)
}
string(4) "key2"
array(10) {
  ["key"]=>
  string(4) "key2"
  ["value"]=>
  string(6) "value2"
  ["num_hits"]=>
  int(0)
  ["mtime"]=>
  int(%d)
  ["creation_time"]=>
  int(%d)
  ["deletion_time"]=>
  int(0)
  ["access_time"]=>
  int(%d)
  ["ref_count"]=>
  int(0)
  ["mem_size"]=>
  int(%d)
  ["ttl"]=>
  int(0)
}
string(4) "key3"
array(10) {
  ["key"]=>
  string(4) "key3"
  ["value"]=>
  string(6) "value3"
  ["num_hits"]=>
  int(0)
  ["mtime"]=>
  int(%d)
  ["creation_time"]=>
  int(%d)
  ["deletion_time"]=>
  int(0)
  ["access_time"]=>
  int(%d)
  ["ref_count"]=>
  int(0)
  ["mem_size"]=>
  int(%d)
  ["ttl"]=>
  int(0)
}
string(4) "key4"
array(10) {
  ["key"]=>
  string(4) "key4"
  ["value"]=>
  string(6) "value4"
  ["num_hits"]=>
  int(0)
  ["mtime"]=>
  int(%d)
  ["creation_time"]=>
  int(%d)
  ["deletion_time"]=>
  int(0)
  ["access_time"]=>
  int(%d)
  ["ref_count"]=>
  int(0)
  ["mem_size"]=>
  int(%d)
  ["ttl"]=>
  int(0)
}
string(4) "key5"
array(10) {
  ["key"]=>
  string(4) "key5"
  ["value"]=>
  string(6) "value5"
  ["num_hits"]=>
  int(0)
  ["mtime"]=>
  int(%d)
  ["creation_time"]=>
  int(%d)
  ["deletion_time"]=>
  int(0)
  ["access_time"]=>
  int(%d)
  ["ref_count"]=>
  int(0)
  ["mem_size"]=>
  int(%d)
  ["ttl"]=>
  int(0)
}
string(4) "key6"
array(10) {
  ["key"]=>
  string(4) "key6"
  ["value"]=>
  string(6) "value6"
  ["num_hits"]=>
  int(0)
  ["mtime"]=>
  int(%d)
  ["creation_time"]=>
  int(%d)
  ["deletion_time"]=>
  int(0)
  ["access_time"]=>
  int(%d)
  ["ref_count"]=>
  int(0)
  ["mem_size"]=>
  int(%d)
  ["ttl"]=>
  int(0)
}
string(4) "key7"
array(10) {
  ["key"]=>
  string(4) "key7"
  ["value"]=>
  string(6) "value7"
  ["num_hits"]=>
  int(0)
  ["mtime"]=>
  int(%d)
  ["creation_time"]=>
  int(%d)
  ["deletion_time"]=>
  int(0)
  ["access_time"]=>
  int(%d)
  ["ref_count"]=>
  int(0)
  ["mem_size"]=>
  int(%d)
  ["ttl"]=>
  int(0)
}
string(4) "key8"
array(10) {
  ["key"]=>
  string(4) "key8"
  ["value"]=>
  string(6) "value8"
  ["num_hits"]=>
  int(0)
  ["mtime"]=>
  int(%d)
  ["creation_time"]=>
  int(%d)
  ["deletion_time"]=>
  int(0)
  ["access_time"]=>
  int(%d)
  ["ref_count"]=>
  int(0)
  ["mem_size"]=>
  int(%d)
  ["ttl"]=>
  int(0)
}
string(4) "key9"
array(10) {
  ["key"]=>
  string(4) "key9"
  ["value"]=>
  string(6) "value9"
  ["num_hits"]=>
  int(0)
  ["mtime"]=>
  int(%d)
  ["creation_time"]=>
  int(%d)
  ["deletion_time"]=>
  int(0)
  ["access_time"]=>
  int(%d)
  ["ref_count"]=>
  int(0)
  ["mem_size"]=>
  int(%d)
  ["ttl"]=>
  int(0)
}
string(5) "key10"
array(10) {
  ["key"]=>
  string(5) "key10"
  ["value"]=>
  string(7) "value10"
  ["num_hits"]=>
  int(0)
  ["mtime"]=>
  int(%d)
  ["creation_time"]=>
  int(%d)
  ["deletion_time"]=>
  int(0)
  ["access_time"]=>
  int(%d)
  ["ref_count"]=>
  int(0)
  ["mem_size"]=>
  int(%d)
  ["ttl"]=>
  int(0)
}
============================

IT #12
============================
string(4) "key0"
array(9) {
  ["key"]=>
  string(4) "key0"
  ["value"]=>
  string(6) "value0"
  ["num_hits"]=>
  int(0)
  ["mtime"]=>
  int(%d)
  ["creation_time"]=>
  int(%d)
  ["deletion_time"]=>
  int(0)
  ["access_time"]=>
  int(%d)
  ["ref_count"]=>
  int(0)
  ["mem_size"]=>
  int(%d)
}
string(4) "key1"
array(9) {
  ["key"]=>
  string(4) "key1"
  ["value"]=>
  string(6) "value1"
  ["num_hits"]=>
  int(0)
  ["mtime"]=>
  int(%d)
  ["creation_time"]=>
  int(%d)
  ["deletion_time"]=>
  int(0)
  ["access_time"]=>
  int(%d)
  ["ref_count"]=>
  int(0)
  ["mem_size"]=>
  int(%d)
}
string(4) "key2"
array(9) {
  ["key"]=>
  string(4) "key2"
  ["value"]=>
  string(6) "value2"
  ["num_hits"]=>
  int(0)
  ["mtime"]=>
  int(%d)
  ["creation_time"]=>
  int(%d)
  ["deletion_time"]=>
  int(0)
  ["access_time"]=>
  int(%d)
  ["ref_count"]=>
  int(0)
  ["mem_size"]=>
  int(%d)
}
string(4) "key3"
array(9) {
  ["key"]=>
  string(4) "key3"
  ["value"]=>
  string(6) "value3"
  ["num_hits"]=>
  int(0)
  ["mtime"]=>
  int(%d)
  ["creation_time"]=>
  int(%d)
  ["deletion_time"]=>
  int(0)
  ["access_time"]=>
  int(%d)
  ["ref_count"]=>
  int(0)
  ["mem_size"]=>
  int(%d)
}
string(4) "key4"
array(9) {
  ["key"]=>
  string(4) "key4"
  ["value"]=>
  string(6) "value4"
  ["num_hits"]=>
  int(0)
  ["mtime"]=>
  int(%d)
  ["creation_time"]=>
  int(%d)
  ["deletion_time"]=>
  int(0)
  ["access_time"]=>
  int(%d)
  ["ref_count"]=>
  int(0)
  ["mem_size"]=>
  int(%d)
}
string(4) "key5"
array(9) {
  ["key"]=>
  string(4) "key5"
  ["value"]=>
  string(6) "value5"
  ["num_hits"]=>
  int(0)
  ["mtime"]=>
  int(%d)
  ["creation_time"]=>
  int(%d)
  ["deletion_time"]=>
  int(0)
  ["access_time"]=>
  int(%d)
  ["ref_count"]=>
  int(0)
  ["mem_size"]=>
  int(%d)
}
string(4) "key6"
array(9) {
  ["key"]=>
  string(4) "key6"
  ["value"]=>
  string(6) "value6"
  ["num_hits"]=>
  int(0)
  ["mtime"]=>
  int(%d)
  ["creation_time"]=>
  int(%d)
  ["deletion_time"]=>
  int(0)
  ["access_time"]=>
  int(%d)
  ["ref_count"]=>
  int(0)
  ["mem_size"]=>
  int(%d)
}
string(4) "key7"
array(9) {
  ["key"]=>
  string(4) "key7"
  ["value"]=>
  string(6) "value7"
  ["num_hits"]=>
  int(0)
  ["mtime"]=>
  int(%d)
  ["creation_time"]=>
  int(%d)
  ["deletion_time"]=>
  int(0)
  ["access_time"]=>
  int(%d)
  ["ref_count"]=>
  int(0)
  ["mem_size"]=>
  int(%d)
}
string(4) "key8"
array(9) {
  ["key"]=>
  string(4) "key8"
  ["value"]=>
  string(6) "value8"
  ["num_hits"]=>
  int(0)
  ["mtime"]=>
  int(%d)
  ["creation_time"]=>
  int(%d)
  ["deletion_time"]=>
  int(0)
  ["access_time"]=>
  int(%d)
  ["ref_count"]=>
  int(0)
  ["mem_size"]=>
  int(%d)
}
string(4) "key9"
array(9) {
  ["key"]=>
  string(4) "key9"
  ["value"]=>
  string(6) "value9"
  ["num_hits"]=>
  int(0)
  ["mtime"]=>
  int(%d)
  ["creation_time"]=>
  int(%d)
  ["deletion_time"]=>
  int(0)
  ["access_time"]=>
  int(%d)
  ["ref_count"]=>
  int(0)
  ["mem_size"]=>
  int(%d)
}
string(5) "key10"
array(9) {
  ["key"]=>
  string(5) "key10"
  ["value"]=>
  string(7) "value10"
  ["num_hits"]=>
  int(0)
  ["mtime"]=>
  int(%d)
  ["creation_time"]=>
  int(%d)
  ["deletion_time"]=>
  int(0)
  ["access_time"]=>
  int(%d)
  ["ref_count"]=>
  int(0)
  ["mem_size"]=>
  int(%d)
}
============================

IT #13
============================
string(4) "key0"
array(3) {
  ["key"]=>
  string(4) "key0"
  ["num_hits"]=>
  int(0)
  ["mem_size"]=>
  int(%d)
}
string(4) "key1"
array(3) {
  ["key"]=>
  string(4) "key1"
  ["num_hits"]=>
  int(0)
  ["mem_size"]=>
  int(%d)
}
string(4) "key2"
array(3) {
  ["key"]=>
  string(4) "key2"
  ["num_hits"]=>
  int(0)
  ["mem_size"]=>
  int(%d)
}
string(4) "key3"
array(3) {
  ["key"]=>
  string(4) "key3"
  ["num_hits"]=>
  int(0)
  ["mem_size"]=>
  int(%d)
}
string(4) "key4"
array(3) {
  ["key"]=>
  string(4) "key4"
  ["num_hits"]=>
  int(0)
  ["mem_size"]=>
  int(%d)
}
string(4) "key5"
array(3) {
  ["key"]=>
  string(4) "key5"
  ["num_hits"]=>
  int(0)
  ["mem_size"]=>
  int(%d)
}
string(4) "key6"
array(3) {
  ["key"]=>
  string(4) "key6"
  ["num_hits"]=>
  int(0)
  ["mem_size"]=>
  int(%d)
}
string(4) "key7"
array(3) {
  ["key"]=>
  string(4) "key7"
  ["num_hits"]=>
  int(0)
  ["mem_size"]=>
  int(%d)
}
string(4) "key8"
array(3) {
  ["key"]=>
  string(4) "key8"
  ["num_hits"]=>
  int(0)
  ["mem_size"]=>
  int(%d)
}
string(4) "key9"
array(3) {
  ["key"]=>
  string(4) "key9"
  ["num_hits"]=>
  int(0)
  ["mem_size"]=>
  int(%d)
}
string(5) "key10"
array(3) {
  ["key"]=>
  string(5) "key10"
  ["num_hits"]=>
  int(0)
  ["mem_size"]=>
  int(%d)
}
============================

===DONE===
apcu-5.1.23/tests/iterator_007.phpt0000664000175000017500000000256714523735540016010 0ustar  nikicnikic--TEST--
APC: APCIterator Overwriting the ctor
--SKIPIF--

--INI--
apc.enabled=1
apc.enable_cli=1
--FILE--
rewind();
} catch (Error $e) {
    echo $e->getMessage(), "\n";
}
try {
    $obj->current();
} catch (Error $e) {
    echo $e->getMessage(), "\n";
}
try {
    $obj->key();
} catch (Error $e) {
    echo $e->getMessage(), "\n";
}
try {
    $obj->next();
} catch (Error $e) {
    echo $e->getMessage(), "\n";
}
try {
    $obj->valid();
} catch (Error $e) {
    echo $e->getMessage(), "\n";
}
try {
    $obj->getTotalHits();
} catch (Error $e) {
    echo $e->getMessage(), "\n";
}
try {
    $obj->getTotalSize();
} catch (Error $e) {
    echo $e->getMessage(), "\n";
}
try {
    $obj->getTotalCount();
} catch (Error $e) {
    echo $e->getMessage(), "\n";
}
try {
    apcu_delete($obj);
} catch (Error $e) {
    echo $e->getMessage(), "\n";
}
?>
--EXPECT--
Trying to use uninitialized APCUIterator
Trying to use uninitialized APCUIterator
Trying to use uninitialized APCUIterator
Trying to use uninitialized APCUIterator
Trying to use uninitialized APCUIterator
Trying to use uninitialized APCUIterator
Trying to use uninitialized APCUIterator
Trying to use uninitialized APCUIterator
Trying to use uninitialized APCUIterator
apcu-5.1.23/tests/iterator_008.phpt0000664000175000017500000000100014523735540015766 0ustar  nikicnikic--TEST--
APC: APCIterator array
--SKIPIF--

--INI--
apc.enabled=1
apc.enable_cli=1
--FILE--
$value) {
  $vals[$key] = $value['key'];
}
ksort($vals);
var_dump($vals);

?>
===DONE===
--EXPECT--
array(3) {
  ["key1"]=>
  string(4) "key1"
  ["key7"]=>
  string(4) "key7"
  ["key9"]=>
  string(4) "key9"
}
===DONE===
apcu-5.1.23/tests/iterator_009.phpt0000664000175000017500000000057614523735540016010 0ustar  nikicnikic--TEST--
APC: APCIterator key invalidated between key() calls
--SKIPIF--

--INI--
apc.enabled=1
apc.enable_cli=1
--FILE--
rewind();
var_dump($it->key());
apcu_delete("foo");
apcu_store("bar", 0);
var_dump($it->key());

?>
--EXPECT--
string(3) "foo"
string(3) "foo"
apcu-5.1.23/tests/iterator_010.phpt0000664000175000017500000000165614523735540016000 0ustar  nikicnikic--TEST--
APC: APCIterator shows entries older than global TTL
--SKIPIF--

--INI--
apc.enabled=1
apc.enable_cli=1
apc.use_request_time=1
apc.ttl=1
--FILE--
getTotalCount()}\n\n";
}

apcu_store("no_ttl", "a");
apcu_store("ttl", "a", 3);

echo "Initial state:\n";
printInfo();

echo "T+2:\n";
apcu_inc_request_time(2);
printInfo();

echo "T+4:\n";
apcu_inc_request_time(2);
printInfo();

?>
--EXPECT--
Initial state:
array(2) {
  [0]=>
  string(6) "no_ttl"
  [1]=>
  string(3) "ttl"
}
Total: 2

T+2:
array(2) {
  [0]=>
  string(6) "no_ttl"
  [1]=>
  string(3) "ttl"
}
Total: 2

T+4:
array(1) {
  [0]=>
  string(6) "no_ttl"
}
Total: 1
apcu-5.1.23/tests/iterator_011.phpt0000664000175000017500000000123114523735540015766 0ustar  nikicnikic--TEST--
APCUIterator key() and current() on invalid iterator
--SKIPIF--

--INI--
apc.enabled=1
apc.enable_cli=1
--FILE--
key());
var_dump($it->current());
$it->next();

try {
    var_dump($it->key());
} catch (Error $e) {
    echo $e->getMessage(), "\n";
}
try {
    var_dump($it->current());
} catch (Error $e) {
    echo $e->getMessage(), "\n";
}

?>
--EXPECT--
string(4) "key1"
array(1) {
  ["value"]=>
  string(6) "value1"
}
Cannot call key() on invalid iterator
Cannot call current() on invalid iterator
apcu-5.1.23/tests/not_enough_shm.phpt0000664000175000017500000000051114523735540016570 0ustar  nikicnikic--TEST--
Error if cache structures cannot be allocated in SHM
--INI--
apc.enabled=1
apc.enable_cli=1
apc.shm_size=1M
apc.entries_hint=1000000
--FILE--
Irrelevant
--EXPECTF--
%A: Unable to allocate %d bytes of shared memory for cache structures. Either apc.shm_size is too small or apc.entries_hint too large in Unknown on line 0
apcu-5.1.23/tests/server_test.inc0000664000175000017500000001033714523735540015726 0ustar  nikicnikic STDIN,
		1 => STDOUT,
		2 => STDERR,
	);

	if (!$php_args) {
		$ext = (substr(PHP_OS, 0, 3) == 'WIN') ? 'php_apcu.dll' : 'apcu.so';
		if (substr(PHP_OS, 0, 3) == 'WIN') {
			$part0 = 8 == PHP_INT_SIZE ? "x64" : "";
			$part1 = ZEND_DEBUG_BUILD ? "Debug" : "Release";
			$part1 = PHP_ZTS ? ($part1 . "_TS") : $part1;
			$php_args = "-d extension_dir=$doc_root/../$part0/$part1";
		} else {
			$php_args = "-d extension_dir=$doc_root/../modules";
		}
		$php_args = "$php_args -d extension=$ext";
	}

	if ($php_opts) {
		$php_args = "$php_args -d " . implode(' -d ', $php_opts);;
	}

	if (substr(PHP_OS, 0, 3) == 'WIN') {
		$cmd = "{$php_executable} -n $php_args -t {$doc_root} -S $host:$port";
		if (!$no_router) {
			$cmd .= " {$router}";
		}

		$descriptorspec[2] = array('pipe', 'w');
		$handle = proc_open(addslashes($cmd), $descriptorspec, $pipes, $doc_root, NULL, array("bypass_shell" => true,  "suppress_errors" => true));
	} else {
		$cmd = "exec {$php_executable} -n $php_args -t {$doc_root} -S $host:$port";
		if (!$no_router) {
			$cmd .= " {$doc_root}/{$router}";
		}
		$cmd .= " 2>/dev/null";

		$handle = proc_open($cmd, $descriptorspec, $pipes, $doc_root);
	}

	// note: even when server prints 'Listening on localhost:8964...Press Ctrl-C to quit.'
	//       it might not be listening yet...need to wait until fsockopen() call returns
	// Let this wait for up to 10 seconds to avoid spurious failures with valgrind.
    $i = 0;
    while (($i++ < 100) && !connection_test($host, $port)) {
        usleep(100000);
    }

	return $handle;
}

function server_start($code = 'echo "Hello world";', $php_opts = array(), $no_router = FALSE)
{
	global $doc_root, $router, $handles, $ports, $num_servers;


	if ($code) {
		file_put_contents($doc_root . '/' . $router, '');
	}

	for ($i = 0; $i < $num_servers; $i++) {
		$h = server_start_one(PHP_CLI_SERVER_HOSTNAME, PHP_CLI_SERVER_PORT+$i, $code, $php_opts, $no_router);
		$handles[] = $h;
	}

	register_shutdown_function(
		function($handles) use($router) {
			foreach ($handles as $handle) {
				proc_terminate($handle);
			}
			@unlink(__DIR__ . "/{$router}");
		},
			$handles
		);
	// don't bother sleeping, server is already up
	// server can take a variable amount of time to be up, so just sleeping a guessed amount of time
	// does not work. this is why tests sometimes pass and sometimes fail. to get a reliable pass
	// sleeping doesn't work.
}

function get_response($fp, $data_only = true)
{
	$s = '';

	while (!feof($fp)) {
		$s .= fgets($fp);
	}

	if ($data_only) {
		$parts = explode("\r\n\r\n", $s);
		$s = $parts[1];
	}

	return $s;
}


function connection_test($host, $port)
{
	$port = intval($port)?:80;

	$fp = @fsockopen($host, $port, $errno, $errstr, 10);
	if (!$fp) {
		return false;
	}

	$send = "GET / HTTP/1.1\nHost: {$host}\r\n\r\n";

	/* will not out here, just test if the connection has worked*/
	if(@fwrite($fp, $send)) {
		get_response($fp);
		fclose($fp);

		return true;
	}

	@fclose($fp);

	return false;
}

function run_test_simple($request_uri = NULL)
{
    global $num_servers;
	$send = "GET /" . $request_uri ." HTTP/1.1\nHost: " . PHP_CLI_SERVER_HOSTNAME . "\r\n\r\n";

	for ($i = 0; $i < $num_servers; $i++) {
		run_test(PHP_CLI_SERVER_HOSTNAME, PHP_CLI_SERVER_PORT+$i, $send);
	}
}

function run_test($host, $port, $send)
{
	$fp = fsockopen($host, $port, $errno, $errstr, 10);
	if (!$fp) {
	  die(sprintf("connect failed errno=%d errstr='%s'", $errno, $errstr));
	}

	if(fwrite($fp, $send)) {
		echo get_response($fp);
	}

	fclose($fp);
}
apcu-5.1.23/tests/skipif.inc0000664000175000017500000000011714523735540014641 0ustar  nikicnikic
apcu-5.1.23/tests/sma001.phpt0000664000175000017500000000107714523735540014565 0ustar  nikicnikic--TEST--
Test SMA behavior #1
--INI--
apc.enabled=1
apc.enable_cli=1
apc.shm_size=16M
--FILE--

===DONE===
--EXPECT--
===DONE===
apcu-5.1.23/tests/typed_prop.phpt0000664000175000017500000000124614523735540015747 0ustar  nikicnikic--TEST--
Success parameters should respect property types
--SKIPIF--
=') or die('skip Requires PHP >= 7.4');
?>
--INI--
apc.enabled=1
apc.enable_cli=1
--FILE--
bool);
var_dump($test->bool);
try {
    apcu_fetch('foo', $test->array);
} catch (Error $e) {
    echo $e->getMessage(), "\n";
}
var_dump($test->array);

?>
--EXPECTF--
bool(true)
Cannot assign %s to reference held by property Test::$array of type array
array(0) {
}
apcu-5.1.23/tests/data/abc.data0000664000175000017500000000001314523735540015145 0ustar  nikicnikics:3:"123";
apcu-5.1.23/tests/bad/abc.data0000664000175000017500000000001114523735540014760 0ustar  nikicnikics:3:"123
apcu-5.1.23/apc_api.h0000664000175000017500000000235514523735540013272 0ustar  nikicnikic/*
  +----------------------------------------------------------------------+
  | APCu                                                                 |
  +----------------------------------------------------------------------+
  | Copyright (c) 2013 The PHP Group                                     |
  +----------------------------------------------------------------------+
  | This source file is subject to version 3.01 of the PHP 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.php.net/license/3_01.txt                                  |
  | If you did not receive a copy of the PHP license and are unable to   |
  | obtain it through the world-wide-web, please send a note to          |
  | license@php.net so we can mail you a copy immediately.               |
  +----------------------------------------------------------------------+
  | Author: Joe Watkins                          |
  +----------------------------------------------------------------------+
 */

#ifndef APC_API_H
#define APC_API_H

#include "apc.h"
#include "apc_lock.h"
#include "apc_sma.h"
#include "apc_cache.h"

#endif
apcu-5.1.23/apc_arginfo.h0000664000175000017500000000016114523735540014137 0ustar  nikicnikic#if PHP_VERSION_ID < 80000
# include "php_apc_legacy_arginfo.h"
#else
# error Not supported on PHP >= 8.0
#endif
apcu-5.1.23/php_apc.stub.php0000664000175000017500000000241514523735540014621 0ustar  nikicnikic              |
  |          George Schlossnagle                      |
  |          Rasmus Lerdorf                              |
  |          Arun C. Murthy                         |
  |          Gopal Vijayaraghavan                  |
  +----------------------------------------------------------------------+

   This software was contributed to PHP by Community Connect Inc. in 2002
   and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1.
   Future revisions and derivatives of this source code must acknowledge
   Community Connect Inc. as the original contributor of this module by
   leaving this note intact in the source code.

   All other licensing and usage conditions are those of the PHP Group.

 */

#include "apc.h"
#include "apc_cache.h"
#include "apc_globals.h"
#include "php.h"

/* {{{ console display functions */
#define APC_PRINT_FUNCTION(name, verbosity)					\
	void apc_##name(const char *format, ...)				\
	{									\
		va_list args;							\
										\
		va_start(args, format);						\
		php_verror(NULL, "", verbosity, format, args);			\
		va_end(args);							\
	}

APC_PRINT_FUNCTION(error, E_ERROR)
APC_PRINT_FUNCTION(warning, E_WARNING)
APC_PRINT_FUNCTION(notice, E_NOTICE)

#ifdef APC_DEBUG
APC_PRINT_FUNCTION(debug, E_NOTICE)
#else
void apc_debug(const char *format, ...) {}
#endif
/* }}} */

/* {{{ apc_flip_hash */
HashTable* apc_flip_hash(HashTable *hash) {
	zval data, *entry;
	HashTable *new_hash;

	if(hash == NULL) return hash;

	ZVAL_LONG(&data, 1);

	ALLOC_HASHTABLE(new_hash);
	zend_hash_init(new_hash, zend_hash_num_elements(hash), NULL, ZVAL_PTR_DTOR, 0);

	ZEND_HASH_FOREACH_VAL(hash, entry) {
		ZVAL_DEREF(entry);
		if (Z_TYPE_P(entry) == IS_STRING) {
			zend_hash_update(new_hash, Z_STR_P(entry), &data);
		} else {
			zend_hash_index_update(new_hash, Z_LVAL_P(entry), &data);
		}
	} ZEND_HASH_FOREACH_END();

	return new_hash;
}
/* }}} */

/*
* Serializer API
*/
#define APC_MAX_SERIALIZERS 16

/* pointer to the list of serializers */
static apc_serializer_t apc_serializers[APC_MAX_SERIALIZERS] = {{0,}};
/* }}} */

/* {{{ apc_register_serializer */
PHP_APCU_API int _apc_register_serializer(
        const char* name, apc_serialize_t serialize, apc_unserialize_t unserialize, void *config) {
	int i;
	apc_serializer_t *serializer;

	for(i = 0; i < APC_MAX_SERIALIZERS; i++) {
		serializer = &apc_serializers[i];
		if(!serializer->name) {
			/* empty entry */
			serializer->name = name;
			serializer->serialize = serialize;
			serializer->unserialize = unserialize;
			serializer->config = config;
			if (i < APC_MAX_SERIALIZERS - 1) {
				apc_serializers[i+1].name = NULL;
			}
			return 1;
		}
	}

	return 0;
} /* }}} */

/* {{{ apc_get_serializers */
PHP_APCU_API apc_serializer_t* apc_get_serializers()  {
	return &(apc_serializers[0]);
} /* }}} */

/* {{{ apc_find_serializer */
PHP_APCU_API apc_serializer_t* apc_find_serializer(const char* name) {
	int i;
	apc_serializer_t *serializer;

	for(i = 0; i < APC_MAX_SERIALIZERS; i++) {
		serializer = &apc_serializers[i];
		if(serializer->name && (strcmp(serializer->name, name) == 0)) {
			return serializer;
		}
	}
	return NULL;
} /* }}} */

/*
 * Local variables:
 * tab-width: 4
 * c-basic-offset: 4
 * End:
 * vim>600: noexpandtab sw=4 ts=4 sts=4 fdm=marker
 * vim<600: noexpandtab sw=4 ts=4 sts=4
 */
apcu-5.1.23/apc_cache.c0000664000175000017500000007652714523735540013573 0ustar  nikicnikic/*
  +----------------------------------------------------------------------+
  | APC                                                                  |
  +----------------------------------------------------------------------+
  | Copyright (c) 2006-2011 The PHP Group                                |
  +----------------------------------------------------------------------+
  | This source file is subject to version 3.01 of the PHP 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.php.net/license/3_01.txt                                    |
  | If you did not receive a copy of the PHP license and are unable to   |
  | obtain it through the world-wide-web, please send a note to          |
  | license@php.net so we can mail you a copy immediately.               |
  +----------------------------------------------------------------------+
  | Authors: Daniel Cowgill               |
  |          Rasmus Lerdorf                              |
  |          Arun C. Murthy                         |
  |          Gopal Vijayaraghavan                  |
  +----------------------------------------------------------------------+

   This software was contributed to PHP by Community Connect Inc. in 2002
   and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1.
   Future revisions and derivatives of this source code must acknowledge
   Community Connect Inc. as the original contributor of this module by
   leaving this note intact in the source code.

   All other licensing and usage conditions are those of the PHP Group.

 */

#include "apc_cache.h"
#include "apc_sma.h"
#include "apc_globals.h"
#include "apc_strings.h"
#include "apc_time.h"
#include "php_scandir.h"
#include "SAPI.h"
#include "TSRM.h"
#include "php_main.h"
#include "ext/standard/md5.h"
#include "ext/standard/php_var.h"
#include "zend_smart_str.h"

#if PHP_VERSION_ID < 70300
# define GC_SET_REFCOUNT(ref, rc) (GC_REFCOUNT(ref) = (rc))
# define GC_ADDREF(ref) GC_REFCOUNT(ref)++
#endif

/* If recursive mutexes are used, there is no distinction between read and write locks.
 * As such, if we acquire a read-lock, it's really a write-lock and we are free to perform
 * increments without atomics. */
#ifdef APC_LOCK_RECURSIVE
# define ATOMIC_INC_RLOCKED(a) (a)++
#else
# define ATOMIC_INC_RLOCKED(a) ATOMIC_INC(a)
#endif

/* Defined in apc_persist.c */
apc_cache_entry_t *apc_persist(
		apc_sma_t *sma, apc_serializer_t *serializer, const apc_cache_entry_t *orig_entry);
zend_bool apc_unpersist(zval *dst, const zval *value, apc_serializer_t *serializer);

/* {{{ make_prime */
static int const primes[] = {
  257, /*   256 */
  521, /*   512 */
 1031, /*  1024 */
 2053, /*  2048 */
 3079, /*  3072 */
 4099, /*  4096 */
 5147, /*  5120 */
 6151, /*  6144 */
 7177, /*  7168 */
 8209, /*  8192 */
 9221, /*  9216 */
10243, /* 10240 */
11273, /* 11264 */
12289, /* 12288 */
13313, /* 13312 */
14341, /* 14336 */
15361, /* 15360 */
16411, /* 16384 */
17417, /* 17408 */
18433, /* 18432 */
19457, /* 19456 */
20483, /* 20480 */
30727, /* 30720 */
40961, /* 40960 */
61441, /* 61440 */
81929, /* 81920 */
122887,/* 122880 */
163841,/* 163840 */
245771,/* 245760 */
327689,/* 327680 */
491527,/* 491520 */
655373,/* 655360 */
983063,/* 983040 */
1310627,/* 1310720 */
1474489,/* 1474560 */
1965983,/* 1966080 */
2621347,/* 2621440 */
3276719,/* 3276800 */
3932063,/* 3932160 */
4587431,/* 4587520 */
5242801,/* 5242880 */
6553511,/* 6553600 */
7864243,/* 7864320 */
8847271,/* 8847360 */
9830321,/* 9830400 */
10485667,/* 10485760 */
0      /* sentinel */
};

static int make_prime(int n)
{
	int *k = (int*)primes;
	while(*k) {
		if((*k) > n) return *k;
		k++;
	}
	return *(k-1);
}
/* }}} */

static inline void free_entry(apc_cache_t *cache, apc_cache_entry_t *entry) {
	apc_sma_free(cache->sma, entry);
}

/* {{{ apc_cache_hash_slot
 Note: These calculations can and should be done outside of a lock */
static inline void apc_cache_hash_slot(
		apc_cache_t* cache, zend_string *key, zend_ulong* hash, size_t* slot) {
	*hash = ZSTR_HASH(key);
	*slot = *hash % cache->nslots;
} /* }}} */

static inline zend_bool apc_entry_key_equals(const apc_cache_entry_t *entry, zend_string *key, zend_ulong hash) {
	return ZSTR_H(entry->key) == hash
		&& ZSTR_LEN(entry->key) == ZSTR_LEN(key)
		&& memcmp(ZSTR_VAL(entry->key), ZSTR_VAL(key), ZSTR_LEN(key)) == 0;
}

/* An entry is hard expired if the creation time if older than the per-entry TTL.
 * Hard expired entries must be treated indentially to non-existent entries. */
static zend_bool apc_cache_entry_hard_expired(apc_cache_entry_t *entry, time_t t) {
	return entry->ttl && (time_t) (entry->ctime + entry->ttl) < t;
}

/* An entry is soft expired if no per-entry TTL is set, a global cache TTL is set,
 * and the access time of the entry is older than the global TTL. Soft expired entries
 * are accessible by lookup operation, but may be removed from the cache at any time. */
static zend_bool apc_cache_entry_soft_expired(
		apc_cache_t *cache, apc_cache_entry_t *entry, time_t t) {
	return !entry->ttl && cache->ttl && (time_t) (entry->atime + cache->ttl) < t;
}

static zend_bool apc_cache_entry_expired(
		apc_cache_t *cache, apc_cache_entry_t *entry, time_t t) {
	return apc_cache_entry_hard_expired(entry, t)
		|| apc_cache_entry_soft_expired(cache, entry, t);
}

/* {{{ apc_cache_wlocked_remove_entry  */
static void apc_cache_wlocked_remove_entry(apc_cache_t *cache, apc_cache_entry_t **entry)
{
	apc_cache_entry_t *dead = *entry;

	/* think here is safer */
	*entry = (*entry)->next;

	/* adjust header info */
	if (cache->header->mem_size)
		cache->header->mem_size -= dead->mem_size;

	if (cache->header->nentries)
		cache->header->nentries--;

	/* remove if there are no references */
	if (dead->ref_count <= 0) {
		free_entry(cache, dead);
	} else {
		/* add to gc if there are still refs */
		dead->next = cache->header->gc;
		dead->dtime = time(0);
		cache->header->gc = dead;
	}
}
/* }}} */

/* {{{ apc_cache_wlocked_gc */
static void apc_cache_wlocked_gc(apc_cache_t* cache)
{
	/* This function scans the list of removed cache entries and deletes any
	 * entry whose reference count is zero  or that has been on the gc
	 * list for more than cache->gc_ttl seconds
	 *   (we issue a warning in the latter case).
	 */
	if (!cache->header->gc) {
		return;
	}

	{
		apc_cache_entry_t **entry = &cache->header->gc;
		time_t now = time(0);

		while (*entry != NULL) {
			time_t gc_sec = cache->gc_ttl ? (now - (*entry)->dtime) : 0;

			if (!(*entry)->ref_count || gc_sec > (time_t)cache->gc_ttl) {
				apc_cache_entry_t *dead = *entry;

				/* good ol' whining */
				if (dead->ref_count > 0) {
					apc_debug(
						"GC cache entry '%s' was on gc-list for %ld seconds",
						ZSTR_VAL(dead->key), gc_sec
					);
				}

				/* set next entry */
				*entry = (*entry)->next;

				/* free entry */
				free_entry(cache, dead);
			} else {
				entry = &(*entry)->next;
			}
		}
	}
}
/* }}} */

/* {{{ php serializer */
PHP_APCU_API int APC_SERIALIZER_NAME(php) (APC_SERIALIZER_ARGS)
{
	smart_str strbuf = {0};
	php_serialize_data_t var_hash;

	/* Lock in case apcu is accessed inside Serializer::serialize() */
	BG(serialize_lock)++;
	PHP_VAR_SERIALIZE_INIT(var_hash);
	php_var_serialize(&strbuf, (zval*) value, &var_hash);
	PHP_VAR_SERIALIZE_DESTROY(var_hash);
	BG(serialize_lock)--;

	if (EG(exception)) {
		smart_str_free(&strbuf);
		strbuf.s = NULL;
	}

	if (strbuf.s != NULL) {
		*buf = (unsigned char *)estrndup(ZSTR_VAL(strbuf.s), ZSTR_LEN(strbuf.s));
		if (*buf == NULL)
			return 0;

		*buf_len = ZSTR_LEN(strbuf.s);
		smart_str_free(&strbuf);
		return 1;
	}
	return 0;
} /* }}} */

/* {{{ php unserializer */
PHP_APCU_API int APC_UNSERIALIZER_NAME(php) (APC_UNSERIALIZER_ARGS)
{
	const unsigned char *tmp = buf;
	php_unserialize_data_t var_hash;
	int result;

	/* Lock in case apcu is accessed inside Serializer::unserialize() */
	BG(serialize_lock)++;
	PHP_VAR_UNSERIALIZE_INIT(var_hash);
	result = php_var_unserialize(value, &tmp, buf + buf_len, &var_hash);
	PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
	BG(serialize_lock)--;
	
	if (!result) {
		php_error_docref(NULL, E_NOTICE, "Error at offset %ld of %ld bytes", (zend_long)(tmp - buf), (zend_long)buf_len);
		ZVAL_NULL(value);
		return 0;
	}
	return 1;
} /* }}} */

/* {{{ apc_cache_create */
PHP_APCU_API apc_cache_t* apc_cache_create(apc_sma_t* sma, apc_serializer_t* serializer, zend_long size_hint, zend_long gc_ttl, zend_long ttl, zend_long smart, zend_bool defend) {
	apc_cache_t* cache;
	zend_long cache_size;
	size_t nslots;

	/* calculate number of slots */
	nslots = make_prime(size_hint > 0 ? size_hint : 2000);

	/* allocate pointer by normal means */
	cache = pemalloc(sizeof(apc_cache_t), 1);

	/* calculate cache size for shm allocation */
	cache_size = sizeof(apc_cache_header_t) + nslots*sizeof(apc_cache_entry_t *);

	/* allocate shm */
	cache->shmaddr = apc_sma_malloc(sma, cache_size);

	if (!cache->shmaddr) {
		zend_error_noreturn(E_CORE_ERROR, "Unable to allocate " ZEND_LONG_FMT " bytes of shared memory for cache structures. Either apc.shm_size is too small or apc.entries_hint too large", cache_size);
		return NULL;
	}

	/* zero cache header and hash slots */
	memset(cache->shmaddr, 0, cache_size);

	/* set default header */
	cache->header = (apc_cache_header_t*) cache->shmaddr;

	cache->header->nhits = 0;
	cache->header->nmisses = 0;
	cache->header->nentries = 0;
	cache->header->nexpunges = 0;
	cache->header->gc = NULL;
	cache->header->stime = time(NULL);
	cache->header->state = 0;

	/* set cache options */
	cache->slots = (apc_cache_entry_t **) (((char*) cache->shmaddr) + sizeof(apc_cache_header_t));
	cache->sma = sma;
	cache->serializer = serializer;
	cache->nslots = nslots;
	cache->gc_ttl = gc_ttl;
	cache->ttl = ttl;
	cache->smart = smart;
	cache->defend = defend;

	/* header lock */
	CREATE_LOCK(&cache->header->lock);

	return cache;
} /* }}} */

static inline zend_bool apc_cache_wlocked_insert(
		apc_cache_t *cache, apc_cache_entry_t *new_entry, zend_bool exclusive) {
	zend_string *key = new_entry->key;
	time_t t = new_entry->ctime;

	/* process deleted list  */
	apc_cache_wlocked_gc(cache);

	/* make the insertion */
	{
		apc_cache_entry_t **entry;
		zend_ulong h;
		size_t s;

		/* calculate hash and entry */
		apc_cache_hash_slot(cache, key, &h, &s);

		entry = &cache->slots[s];
		while (*entry) {
			/* check for a match by hash and string */
			if (apc_entry_key_equals(*entry, key, h)) {
				/*
				 * At this point we have found the user cache entry.  If we are doing
				 * an exclusive insert (apc_add) we are going to bail right away if
				 * the user entry already exists and is hard expired.
				 */
				if (exclusive && !apc_cache_entry_hard_expired(*entry, t)) {
					return 0;
				}

				apc_cache_wlocked_remove_entry(cache, entry);
				break;
			}

			/*
			 * This is a bit nasty. The idea here is to do runtime cleanup of the linked list of
			 * entry entries so we don't always have to skip past a bunch of stale entries.
			 */
			if (apc_cache_entry_expired(cache, *entry, t)) {
				apc_cache_wlocked_remove_entry(cache, entry);
				continue;
			}

			/* set next entry */
			entry = &(*entry)->next;
		}

		/* link in new entry */
		new_entry->next = *entry;
		*entry = new_entry;

		cache->header->mem_size += new_entry->mem_size;
		cache->header->nentries++;
		cache->header->ninserts++;
	}

	return 1;
}

static void apc_cache_init_entry(
		apc_cache_entry_t *entry, zend_string *key, const zval* val, const int32_t ttl, time_t t);

/* TODO This function may lead to a deadlock on expunge */
static inline zend_bool apc_cache_store_internal(
		apc_cache_t *cache, zend_string *key, const zval *val,
		const int32_t ttl, const zend_bool exclusive) {
	apc_cache_entry_t tmp_entry, *entry;
	time_t t = apc_time();

	if (apc_cache_defense(cache, key, t)) {
		return 0;
	}

	/* initialize the entry for insertion */
	apc_cache_init_entry(&tmp_entry, key, val, ttl, t);
	entry = apc_persist(cache->sma, cache->serializer, &tmp_entry);
	if (!entry) {
		return 0;
	}

	/* execute an insertion */
	if (!apc_cache_wlocked_insert(cache, entry, exclusive)) {
		free_entry(cache, entry);
		return 0;
	}

	return 1;
}

/* Find entry, without updating stat counters or access time */
static inline apc_cache_entry_t *apc_cache_rlocked_find_nostat(
		apc_cache_t *cache, zend_string *key, time_t t) {
	apc_cache_entry_t *entry;
	zend_ulong h;
	size_t s;

	/* calculate hash and slot */
	apc_cache_hash_slot(cache, key, &h, &s);

	entry = cache->slots[s];
	while (entry) {
		/* check for a matching key by has and identifier */
		if (apc_entry_key_equals(entry, key, h)) {
			/* Check to make sure this entry isn't expired by a hard TTL */
			if (apc_cache_entry_hard_expired(entry, t)) {
				break;
			}

			return entry;
		}

		entry = entry->next;
	}

	return NULL;
}

/* Find entry, updating stat counters and access time */
static inline apc_cache_entry_t *apc_cache_rlocked_find(
		apc_cache_t *cache, zend_string *key, time_t t) {
	apc_cache_entry_t *entry;
	zend_ulong h;
	size_t s;

	/* calculate hash and slot */
	apc_cache_hash_slot(cache, key, &h, &s);

	entry = cache->slots[s];
	while (entry) {
		/* check for a matching key by has and identifier */
		if (apc_entry_key_equals(entry, key, h)) {
			/* Check to make sure this entry isn't expired by a hard TTL */
			if (apc_cache_entry_hard_expired(entry, t)) {
				break;
			}

			ATOMIC_INC_RLOCKED(cache->header->nhits);
			ATOMIC_INC_RLOCKED(entry->nhits);
			entry->atime = t;

			return entry;
		}

		entry = entry->next;
	}

	ATOMIC_INC_RLOCKED(cache->header->nmisses);
	return NULL;
}

static inline apc_cache_entry_t *apc_cache_rlocked_find_incref(
		apc_cache_t *cache, zend_string *key, time_t t) {
	apc_cache_entry_t *entry = apc_cache_rlocked_find(cache, key, t);
	if (!entry) {
		return NULL;
	}

	ATOMIC_INC_RLOCKED(entry->ref_count);
	return entry;
}

/* {{{ apc_cache_store */
PHP_APCU_API zend_bool apc_cache_store(
		apc_cache_t* cache, zend_string *key, const zval *val,
		const int32_t ttl, const zend_bool exclusive) {
	apc_cache_entry_t tmp_entry, *entry;
	time_t t = apc_time();
	zend_bool ret = 0;

	if (!cache) {
		return 0;
	}

	/* run cache defense */
	if (apc_cache_defense(cache, key, t)) {
		return 0;
	}

	/* initialize the entry for insertion */
	apc_cache_init_entry(&tmp_entry, key, val, ttl, t);
	entry = apc_persist(cache->sma, cache->serializer, &tmp_entry);
	if (!entry) {
		return 0;
	}

	/* execute an insertion */
	if (!apc_cache_wlock(cache)) {
		free_entry(cache, entry);
		return 0;
	}

	php_apc_try {
		ret = apc_cache_wlocked_insert(cache, entry, exclusive);
	} php_apc_finally {
		apc_cache_wunlock(cache);
	} php_apc_end_try();

	if (!ret) {
		free_entry(cache, entry);
	}

	return ret;
} /* }}} */

#ifndef ZTS
/* {{{ data_unserialize */
static zval data_unserialize(const char *filename)
{
	zval retval;
	zend_long len = 0;
	zend_stat_t sb;
	char *contents, *tmp;
	FILE *fp;
	php_unserialize_data_t var_hash = {0,};

	if(VCWD_STAT(filename, &sb) == -1) {
		return EG(uninitialized_zval);
	}

	fp = fopen(filename, "rb");

	len = sizeof(char)*sb.st_size;

	tmp = contents = malloc(len);

	if(!contents) {
		fclose(fp);
		return EG(uninitialized_zval);
	}

	if(fread(contents, 1, len, fp) < 1) {
		fclose(fp);
		free(contents);
		return EG(uninitialized_zval);
	}

	ZVAL_UNDEF(&retval);

	PHP_VAR_UNSERIALIZE_INIT(var_hash);

	/* I wish I could use json */
	if(!php_var_unserialize(&retval, (const unsigned char**)&tmp, (const unsigned char*)(contents+len), &var_hash)) {
		fclose(fp);
		free(contents);
		return EG(uninitialized_zval);
	}

	PHP_VAR_UNSERIALIZE_DESTROY(var_hash);

	free(contents);
	fclose(fp);

	return retval;
}

static int apc_load_data(apc_cache_t* cache, const char *data_file)
{
	char *p;
	char key[MAXPATHLEN] = {0,};
	size_t key_len;
	zval data;

	p = strrchr(data_file, DEFAULT_SLASH);

	if(p && p[1]) {
		strlcpy(key, p+1, sizeof(key));
		p = strrchr(key, '.');

		if(p) {
			p[0] = '\0';
			key_len = strlen(key);

			data = data_unserialize(data_file);
			if(Z_TYPE(data) != IS_UNDEF) {
				zend_string *name = zend_string_init(key, key_len, 0);
				apc_cache_store(
					cache, name, &data, 0, 1);
				zend_string_release(name);
				zval_dtor(&data);
			}
			return 1;
		}
	}

	return 0;
}
#endif

/* {{{ apc_cache_preload shall load the prepared data files in path into the specified cache */
PHP_APCU_API zend_bool apc_cache_preload(apc_cache_t* cache, const char *path)
{
#ifndef ZTS
	zend_bool result = 0;
	char file[MAXPATHLEN]={0,};
	int ndir, i;
	char *p = NULL;
	struct dirent **namelist = NULL;

	if ((ndir = php_scandir(path, &namelist, 0, php_alphasort)) > 0) {
		for (i = 0; i < ndir; i++) {
			/* check for extension */
			if (!(p = strrchr(namelist[i]->d_name, '.'))
					|| (p && strcmp(p, ".data"))) {
				free(namelist[i]);
				continue;
			}

			snprintf(file, MAXPATHLEN, "%s%c%s",
					path, DEFAULT_SLASH, namelist[i]->d_name);

			if(apc_load_data(cache, file)) {
				result = 1;
			}
			free(namelist[i]);
		}
		free(namelist);
	}
	return result;
#else
	apc_error("Cannot load data from apc.preload_path=%s in thread-safe mode", path);
	return 0;
#endif
} /* }}} */

/* {{{ apc_cache_entry_release */
PHP_APCU_API void apc_cache_entry_release(apc_cache_t *cache, apc_cache_entry_t *entry)
{
	ATOMIC_DEC(entry->ref_count);
}
/* }}} */

/* {{{ apc_cache_detach */
PHP_APCU_API void apc_cache_detach(apc_cache_t *cache)
{
	/* Important: This function should not clean up anything that's in shared memory,
	 * only detach our process-local use of it. In particular locks cannot be destroyed
	 * here. */

	if (!cache) {
		return;
	}

	free(cache);
}
/* }}} */

/* {{{ apc_cache_wlocked_real_expunge */
static void apc_cache_wlocked_real_expunge(apc_cache_t* cache) {
	size_t i;

	/* increment counter */
	cache->header->nexpunges++;

	/* expunge */
	for (i = 0; i < cache->nslots; i++) {
		apc_cache_entry_t **entry = &cache->slots[i];
		while (*entry) {
			apc_cache_wlocked_remove_entry(cache, entry);
		}
	}

	/* set new time so counters make sense */
	cache->header->stime = apc_time();

	/* reset counters */
	cache->header->ninserts = 0;
	cache->header->nentries = 0;
	cache->header->nhits = 0;
	cache->header->nmisses = 0;

	/* resets lastkey */
	memset(&cache->header->lastkey, 0, sizeof(apc_cache_slam_key_t));
} /* }}} */

/* {{{ apc_cache_clear */
PHP_APCU_API void apc_cache_clear(apc_cache_t* cache)
{
	if (!cache) {
		return;
	}

	if (!apc_cache_wlock(cache)) {
		return;
	}

	/* expunge cache */
	apc_cache_wlocked_real_expunge(cache);

	/* set info */
	cache->header->stime = apc_time();
	cache->header->nexpunges = 0;

	apc_cache_wunlock(cache);
}
/* }}} */

/* {{{ apc_cache_default_expunge */
PHP_APCU_API void apc_cache_default_expunge(apc_cache_t* cache, size_t size)
{
	time_t t;
	size_t suitable = 0L;
	size_t available = 0L;

	if (!cache) {
		return;
	}

	/* apc_time() depends on globals, don't read it if there's no cache. This may happen if SHM
	 * is too small and the initial cache creation during MINIT triggers an expunge. */
	t = apc_time();

	/* get the lock for header */
	if (!apc_cache_wlock(cache)) {
		return;
	}

	/* make suitable selection */
	suitable = (cache->smart > 0L) ? (size_t) (cache->smart * size) : (size_t) (cache->sma->size/2);

	/* gc */
	apc_cache_wlocked_gc(cache);

	/* get available */
	available = apc_sma_get_avail_mem(cache->sma);

	/* perform expunge processing */
	if (!cache->ttl) {
		/* check it is necessary to expunge */
		if (available < suitable) {
			apc_cache_wlocked_real_expunge(cache);
		}
	} else {
		/* check that expunge is necessary */
		if (available < suitable) {
			size_t i;

			/* look for junk */
			for (i = 0; i < cache->nslots; i++) {
				apc_cache_entry_t **entry = &cache->slots[i];
				while (*entry) {
					if (apc_cache_entry_expired(cache, *entry, t)) {
						apc_cache_wlocked_remove_entry(cache, entry);
						continue;
					}

					/* grab next entry */
					entry = &(*entry)->next;
				}
			}

			/* if the cache now has space, then reset last key */
			if (apc_sma_get_avail_size(cache->sma, size)) {
				/* wipe lastkey */
				memset(&cache->header->lastkey, 0, sizeof(apc_cache_slam_key_t));
			} else {
				/* with not enough space left in cache, we are forced to expunge */
				apc_cache_wlocked_real_expunge(cache);
			}
		}
	}

	apc_cache_wunlock(cache);
}
/* }}} */

/* {{{ apc_cache_find */
PHP_APCU_API apc_cache_entry_t *apc_cache_find(apc_cache_t* cache, zend_string *key, time_t t)
{
	apc_cache_entry_t *entry;

	if (!cache) {
		return NULL;
	}

	if (!apc_cache_rlock(cache)) {
		return NULL;
	}

	entry = apc_cache_rlocked_find_incref(cache, key, t);
	apc_cache_runlock(cache);

	return entry;
}
/* }}} */

/* {{{ apc_cache_fetch */
PHP_APCU_API zend_bool apc_cache_fetch(apc_cache_t* cache, zend_string *key, time_t t, zval *dst)
{
	apc_cache_entry_t *entry;
	zend_bool retval = 0;

	if (!cache) {
		return 0;
	}

	if (!apc_cache_rlock(cache)) {
		return 0;
	}

	entry = apc_cache_rlocked_find_incref(cache, key, t);
	apc_cache_runlock(cache);

	if (!entry) {
		return 0;
	}

	php_apc_try {
		retval = apc_cache_entry_fetch_zval(cache, entry, dst);
	} php_apc_finally {
		apc_cache_entry_release(cache, entry);
	} php_apc_end_try();

	return retval;
} /* }}} */

/* {{{ apc_cache_exists */
PHP_APCU_API zend_bool apc_cache_exists(apc_cache_t* cache, zend_string *key, time_t t)
{
	apc_cache_entry_t *entry;

	if (!cache) {
		return 0;
	}

	if (!apc_cache_rlock(cache)) {
		return 0;
	}

	entry = apc_cache_rlocked_find_nostat(cache, key, t);
	apc_cache_runlock(cache);

	return entry != NULL;
}
/* }}} */

/* {{{ apc_cache_update */
PHP_APCU_API zend_bool apc_cache_update(
		apc_cache_t *cache, zend_string *key, apc_cache_updater_t updater, void *data,
		zend_bool insert_if_not_found, zend_long ttl)
{
	apc_cache_entry_t *entry;
	zend_bool retval = 0;
	time_t t = apc_time();

	if (!cache) {
		return 0;
	}

retry_update:
	if (!apc_cache_wlock(cache)) {
		return 0;
	}

	entry = apc_cache_rlocked_find_nostat(cache, key, t);
	if (entry) {
		/* Only allow changes to simple values */
		if (Z_TYPE(entry->val) < IS_STRING) {
			retval = updater(cache, entry, data);
			entry->mtime = t;
		}

		apc_cache_wunlock(cache);
		return retval;
	}

	apc_cache_wunlock(cache);
	if (insert_if_not_found) {
		/* Failed to find matching entry. Add key with value 0 and run the updater again. */
		zval val;
		ZVAL_LONG(&val, 0);

		/* We do not check the return value of the exclusive-store (add), as the entry might have
		 * been added between the cache unlock and the store call. In this case we just want to
		 * update the entry created by a different process. */
		apc_cache_store(cache, key, &val, ttl, 1);

		/* Only attempt to perform insertion once. */
		insert_if_not_found = 0;
		goto retry_update;
	}

	return 0;
}
/* }}} */

/* {{{ apc_cache_atomic_update_long */
PHP_APCU_API zend_bool apc_cache_atomic_update_long(
		apc_cache_t *cache, zend_string *key, apc_cache_atomic_updater_t updater, void *data,
		zend_bool insert_if_not_found, zend_long ttl)
{
	apc_cache_entry_t *entry;
	zend_bool retval = 0;
	time_t t = apc_time();

	if (!cache) {
		return 0;
	}

retry_update:
	if (!apc_cache_rlock(cache)) {
		return 0;
	}

	entry = apc_cache_rlocked_find_nostat(cache, key, t);
	if (entry) {
		/* Only supports integers */
		if (Z_TYPE(entry->val) == IS_LONG) {
			retval = updater(cache, &Z_LVAL(entry->val), data);
			entry->mtime = t;
		}

		apc_cache_runlock(cache);
		return retval;
	}

	apc_cache_runlock(cache);
	if (insert_if_not_found) {
		/* Failed to find matching entry. Add key with value 0 and run the updater again. */
		zval val;
		ZVAL_LONG(&val, 0);

		/* We do not check the return value of the exclusive-store (add), as the entry might have
		 * been added between the cache unlock and the store call. In this case we just want to
		 * update the entry created by a different process. */
		apc_cache_store(cache, key, &val, ttl, 1);

		/* Only attempt to perform insertion once. */
		insert_if_not_found = 0;
		goto retry_update;
	}

	return 0;
}
/* }}} */

/* {{{ apc_cache_delete */
PHP_APCU_API zend_bool apc_cache_delete(apc_cache_t *cache, zend_string *key)
{
	apc_cache_entry_t **entry;
	zend_ulong h;
	size_t s;

	if (!cache) {
		return 0;
	}

	/* calculate hash and slot */
	apc_cache_hash_slot(cache, key, &h, &s);

	if (!apc_cache_wlock(cache)) {
		return 0;
	}

	/* find head */
	entry = &cache->slots[s];

	while (*entry) {
		/* check for a match by hash and identifier */
		if (apc_entry_key_equals(*entry, key, h)) {
			/* executing removal */
			apc_cache_wlocked_remove_entry(cache, entry);

			apc_cache_wunlock(cache);
			return 1;
		}

		entry = &(*entry)->next;
	}

	apc_cache_wunlock(cache);
	return 0;
}
/* }}} */

/* {{{ apc_cache_entry_fetch_zval */
PHP_APCU_API zend_bool apc_cache_entry_fetch_zval(
		apc_cache_t *cache, apc_cache_entry_t *entry, zval *dst)
{
	return apc_unpersist(dst, &entry->val, cache->serializer);
}
/* }}} */

/* {{{ apc_cache_make_entry */
static void apc_cache_init_entry(
		apc_cache_entry_t *entry, zend_string *key, const zval *val, const int32_t ttl, time_t t)
{
	entry->ttl = ttl;
	entry->key = key;
	ZVAL_COPY_VALUE(&entry->val, val);

	entry->next = NULL;
	entry->ref_count = 0;
	entry->mem_size = 0;
	entry->nhits = 0;
	entry->ctime = t;
	entry->mtime = t;
	entry->atime = t;
	entry->dtime = 0;
}
/* }}} */

static inline void array_add_long(zval *array, zend_string *key, zend_long lval) {
	zval zv;
	ZVAL_LONG(&zv, lval);
	zend_hash_add_new(Z_ARRVAL_P(array), key, &zv);
}

static inline void array_add_double(zval *array, zend_string *key, double dval) {
	zval zv;
	ZVAL_DOUBLE(&zv, dval);
	zend_hash_add_new(Z_ARRVAL_P(array), key, &zv);
}

/* {{{ apc_cache_link_info */
static zval apc_cache_link_info(apc_cache_t *cache, apc_cache_entry_t *p)
{
	zval link, zv;
	array_init(&link);

	ZVAL_STR(&zv, zend_string_dup(p->key, 0));
	zend_hash_add_new(Z_ARRVAL(link), apc_str_info, &zv);

	array_add_long(&link, apc_str_ttl, p->ttl);
	array_add_double(&link, apc_str_num_hits, (double) p->nhits);
	array_add_long(&link, apc_str_mtime, p->mtime);
	array_add_long(&link, apc_str_creation_time, p->ctime);
	array_add_long(&link, apc_str_deletion_time, p->dtime);
	array_add_long(&link, apc_str_access_time, p->atime);
	array_add_long(&link, apc_str_ref_count, p->ref_count);
	array_add_long(&link, apc_str_mem_size, p->mem_size);

	return link;
}
/* }}} */

/* {{{ apc_cache_info */
PHP_APCU_API zend_bool apc_cache_info(zval *info, apc_cache_t *cache, zend_bool limited)
{
	zval list;
	zval gc;
	zval slots;
	apc_cache_entry_t *p;
	zend_ulong j;

	ZVAL_NULL(info);
	if (!cache) {
		return 0;
	}

	if (!apc_cache_rlock(cache)) {
		return 0;
	}

	php_apc_try {
		array_init(info);
		add_assoc_long(info, "num_slots", cache->nslots);
		array_add_long(info, apc_str_ttl, cache->ttl);
		array_add_double(info, apc_str_num_hits, (double) cache->header->nhits);
		add_assoc_double(info, "num_misses", (double) cache->header->nmisses);
		add_assoc_double(info, "num_inserts", (double) cache->header->ninserts);
		add_assoc_long(info,   "num_entries", cache->header->nentries);
		add_assoc_double(info, "expunges", (double) cache->header->nexpunges);
		add_assoc_long(info, "start_time", cache->header->stime);
		array_add_double(info, apc_str_mem_size, (double) cache->header->mem_size);

#if APC_MMAP
		add_assoc_stringl(info, "memory_type", "mmap", sizeof("mmap")-1);
#else
		add_assoc_stringl(info, "memory_type", "IPC shared", sizeof("IPC shared")-1);
#endif

		if (!limited) {
			size_t i;

			/* For each hashtable slot */
			array_init(&list);
			array_init(&slots);

			for (i = 0; i < cache->nslots; i++) {
				p = cache->slots[i];
				j = 0;
				for (; p != NULL; p = p->next) {
					zval link = apc_cache_link_info(cache, p);
					add_next_index_zval(&list, &link);
					j++;
				}
				if (j != 0) {
					add_index_long(&slots, (zend_ulong)i, j);
				}
			}

			/* For each slot pending deletion */
			array_init(&gc);

			for (p = cache->header->gc; p != NULL; p = p->next) {
				zval link = apc_cache_link_info(cache, p);
				add_next_index_zval(&gc, &link);
			}

			add_assoc_zval(info, "cache_list", &list);
			add_assoc_zval(info, "deleted_list", &gc);
			add_assoc_zval(info, "slot_distribution", &slots);
		}
	} php_apc_finally {
		apc_cache_runlock(cache);
	} php_apc_end_try();

	return 1;
}
/* }}} */

/*
 fetches information about the key provided
*/
PHP_APCU_API void apc_cache_stat(apc_cache_t *cache, zend_string *key, zval *stat) {
	zend_ulong h;
	size_t s;

	ZVAL_NULL(stat);
	if (!cache) {
		return;
	}

	/* calculate hash and slot */
	apc_cache_hash_slot(cache, key, &h, &s);

	if (!apc_cache_rlock(cache)) {
		return;
	}

	php_apc_try {
		/* find head */
		apc_cache_entry_t *entry = cache->slots[s];

		while (entry) {
			/* check for a matching key by has and identifier */
			if (apc_entry_key_equals(entry, key, h)) {
				array_init(stat);
				array_add_long(stat, apc_str_hits, entry->nhits);
				array_add_long(stat, apc_str_access_time, entry->atime);
				array_add_long(stat, apc_str_mtime, entry->mtime);
				array_add_long(stat, apc_str_creation_time, entry->ctime);
				array_add_long(stat, apc_str_deletion_time, entry->dtime);
				array_add_long(stat, apc_str_ttl, entry->ttl);
				array_add_long(stat, apc_str_refs, entry->ref_count);
				break;
			}

			/* next */
			entry = entry->next;
		}
	} php_apc_finally {
		apc_cache_runlock(cache);
	} php_apc_end_try();
}

/* {{{ apc_cache_defense */
PHP_APCU_API zend_bool apc_cache_defense(apc_cache_t *cache, zend_string *key, time_t t)
{
	/* only continue if slam defense is enabled */
	if (cache->defend) {

		/* for copy of locking key struct */
		apc_cache_slam_key_t *last = &cache->header->lastkey;
		pid_t owner_pid = getpid();
#ifdef ZTS
		void ***owner_thread = TSRMLS_CACHE;
#endif

		/* check the hash and length match */
		/* check the time (last second considered slam) and context */
		if (last->hash == ZSTR_HASH(key) &&
			last->len == ZSTR_LEN(key) &&
			last->mtime == t &&
			(last->owner_pid != owner_pid
#if ZTS
			 || last->owner_thread != owner_thread
#endif
			)
		) {
			/* potential cache slam */
			return 1;
		}

		/* sets enough information for an educated guess, but is not exact */
		last->hash = ZSTR_HASH(key);
		last->len = ZSTR_LEN(key);
		last->mtime = t;
		last->owner_pid = owner_pid;
#ifdef ZTS
		last->owner_thread = owner_thread;
#endif
	}

	return 0;
}
/* }}} */

/* {{{ apc_cache_serializer */
PHP_APCU_API void apc_cache_serializer(apc_cache_t* cache, const char* name) {
	if (cache && !cache->serializer) {
		cache->serializer = apc_find_serializer(name);
	}
} /* }}} */

PHP_APCU_API void apc_cache_entry(apc_cache_t *cache, zend_string *key, zend_fcall_info *fci, zend_fcall_info_cache *fcc, zend_long ttl, zend_long now, zval *return_value) {/*{{{*/
	apc_cache_entry_t *entry = NULL;

	if (!cache) {
		return;
	}

	if (!apc_cache_wlock(cache)) {
		return;
	}

	APCG(entry_level)++;
	php_apc_try {
		entry = apc_cache_rlocked_find_incref(cache, key, now);
		if (!entry) {
			int result;
			zval params[1];
			ZVAL_STR_COPY(¶ms[0], key);

			fci->retval = return_value;
			fci->param_count = 1;
			fci->params = params;

			result = zend_call_function(fci, fcc);

			zval_ptr_dtor(¶ms[0]);

			if (result == SUCCESS && !EG(exception)) {
				apc_cache_store_internal(
					cache, key, return_value, (uint32_t) ttl, 1);
			}
		} else {
			apc_cache_entry_fetch_zval(cache, entry, return_value);
			apc_cache_entry_release(cache, entry);
		}
	} php_apc_finally {
		APCG(entry_level)--;
		apc_cache_wunlock(cache);
	} php_apc_end_try();
}
/*}}}*/

/*
 * Local variables:
 * tab-width: 4
 * c-basic-offset: 4
 * End:
 * vim>600: noexpandtab sw=4 ts=4 sts=4 fdm=marker
 * vim<600: noexpandtab sw=4 ts=4 sts=4
 */
apcu-5.1.23/apc_cache.h0000664000175000017500000003203314523735540013560 0ustar  nikicnikic/*
  +----------------------------------------------------------------------+
  | APC                                                                  |
  +----------------------------------------------------------------------+
  | Copyright (c) 2006-2011 The PHP Group                                |
  +----------------------------------------------------------------------+
  | This source file is subject to version 3.01 of the PHP 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.php.net/license/3_01.txt.                                 |
  | If you did not receive a copy of the PHP license and are unable to   |
  | obtain it through the world-wide-web, please send a note to          |
  | license@php.net so we can mail you a copy immediately.               |
  +----------------------------------------------------------------------+
  | Authors: Daniel Cowgill               |
  |          Rasmus Lerdorf                              |
  +----------------------------------------------------------------------+

   This software was contributed to PHP by Community Connect Inc. in 2002
   and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1.
   Future revisions and derivatives of this source code must acknowledge
   Community Connect Inc. as the original contributor of this module by
   leaving this note intact in the source code.

   All other licensing and usage conditions are those of the PHP Group.

 */

#ifndef APC_CACHE_H
#define APC_CACHE_H

#include "apc.h"
#include "apc_sma.h"
#include "apc_lock.h"
#include "apc_globals.h"
#include "TSRM.h"

typedef struct apc_cache_slam_key_t apc_cache_slam_key_t;
struct apc_cache_slam_key_t {
	zend_ulong hash;         /* hash of the key */
	size_t len;              /* length of the key */
	time_t mtime;            /* creation time of this key */
	pid_t owner_pid;         /* the pid that created this key */
#ifdef ZTS
	void ***owner_thread;    /* TSRMLS cache of thread that created this key */
#endif
};

/* {{{ struct definition: apc_cache_entry_t */
typedef struct apc_cache_entry_t apc_cache_entry_t;
struct apc_cache_entry_t {
	zend_string *key;        /* entry key */
	zval val;                /* the zval copied at store time */
	apc_cache_entry_t *next; /* next entry in linked list */
	zend_long ttl;           /* the ttl on this specific entry */
	zend_long ref_count;     /* the reference count of this entry */
	zend_long nhits;         /* number of hits to this entry */
	time_t ctime;            /* time entry was initialized */
	time_t mtime;            /* the mtime of this cached entry */
	time_t dtime;            /* time entry was removed from cache */
	time_t atime;            /* time entry was last accessed */
	zend_long mem_size;      /* memory used */
};
/* }}} */

/* {{{ struct definition: apc_cache_header_t
   Any values that must be shared among processes should go in here. */
typedef struct _apc_cache_header_t {
	apc_lock_t lock;                /* header lock */
	zend_long nhits;                /* hit count */
	zend_long nmisses;              /* miss count */
	zend_long ninserts;             /* insert count */
	zend_long nexpunges;            /* expunge count */
	zend_long nentries;             /* entry count */
	zend_long mem_size;             /* used */
	time_t stime;                   /* start time */
	unsigned short state;           /* cache state */
	apc_cache_slam_key_t lastkey;   /* last key inserted (not necessarily without error) */
	apc_cache_entry_t *gc;          /* gc list */
} apc_cache_header_t; /* }}} */

/* {{{ struct definition: apc_cache_t */
typedef struct _apc_cache_t {
	void* shmaddr;                /* process (local) address of shared cache */
	apc_cache_header_t* header;   /* cache header (stored in SHM) */
	apc_cache_entry_t** slots;    /* array of cache slots (stored in SHM) */
	apc_sma_t* sma;               /* shared memory allocator */
	apc_serializer_t* serializer; /* serializer */
	size_t nslots;                /* number of slots in cache */
	zend_long gc_ttl;            /* maximum time on GC list for a entry */
	zend_long ttl;               /* if slot is needed and entry's access time is older than this ttl, remove it */
	zend_long smart;             /* smart parameter for gc */
	zend_bool defend;             /* defense parameter for runtime */
} apc_cache_t; /* }}} */

/* {{{ typedef: apc_cache_updater_t */
typedef zend_bool (*apc_cache_updater_t)(apc_cache_t*, apc_cache_entry_t*, void* data); /* }}} */

/* {{{ typedef: apc_cache_atomic_updater_t */
typedef zend_bool (*apc_cache_atomic_updater_t)(apc_cache_t*, zend_long*, void* data); /* }}} */

/*
 * apc_cache_create creates the shared memory cache.
 *
 * This function should be called once per process per cache
 *
 * serializer for APCu is set by globals on MINIT and ensured with apc_cache_serializer
 * during execution. Using apc_cache_serializer avoids race conditions between MINIT/RINIT of
 * APCU and the third party serializer. API users can choose to leave this null to use default
 * PHP serializers, or search the list of serializers for the preferred serializer
 *
 * size_hint is a "hint" at the total number entries that will be expected.
 * It determines the physical size of the hash table. Passing 0 for
 * this argument will use a reasonable default value
 *
 * gc_ttl is the maximum time a cache entry may speed on the garbage
 * collection list. This is basically a work around for the inherent
 * unreliability of our reference counting mechanism (see apc_cache_release).
 *
 * ttl is the maximum time a cache entry can idle in a slot in case the slot
 * is needed.  This helps in cleaning up the cache and ensuring that entries
 * hit frequently stay cached and ones not hit very often eventually disappear.
 *
 * for an explanation of smart, see apc_cache_default_expunge
 *
 * defend enables/disables slam defense for this particular cache
 */
PHP_APCU_API apc_cache_t* apc_cache_create(
        apc_sma_t* sma, apc_serializer_t* serializer, zend_long size_hint,
        zend_long gc_ttl, zend_long ttl, zend_long smart, zend_bool defend);
/*
* apc_cache_preload preloads the data at path into the specified cache
*/
PHP_APCU_API zend_bool apc_cache_preload(apc_cache_t* cache, const char* path);

/*
 * apc_cache_detach detaches from the shared memory cache and cleans up
 * local allocations. Under apache, this function can be safely called by
 * the child processes when they exit.
 */
PHP_APCU_API void apc_cache_detach(apc_cache_t* cache);

/*
 * apc_cache_clear empties a cache. This can safely be called at any time.
 */
PHP_APCU_API void apc_cache_clear(apc_cache_t* cache);

/*
 * apc_cache_store creates key, entry and context in which to make an insertion of val into the specified cache
 */
PHP_APCU_API zend_bool apc_cache_store(
        apc_cache_t* cache, zend_string *key, const zval *val,
        const int32_t ttl, const zend_bool exclusive);
/*
 * apc_cache_update updates an entry in place. The updater function must not bailout.
 * The update is performed under write-lock and doesn't have to be atomic.
 */
PHP_APCU_API zend_bool apc_cache_update(
		apc_cache_t *cache, zend_string *key, apc_cache_updater_t updater, void *data,
		zend_bool insert_if_not_found, zend_long ttl);

/*
 * apc_cache_atomic_update_long updates an integer entry in place. The updater function must
 * perform the update atomically, as the update is performed under read-lock.
 */
PHP_APCU_API zend_bool apc_cache_atomic_update_long(
		apc_cache_t *cache, zend_string *key, apc_cache_atomic_updater_t updater, void *data,
		zend_bool insert_if_not_found, zend_long ttl);

/*
 * apc_cache_find searches for a cache entry by its hashed identifier,
 * and returns a pointer to the entry if found, NULL otherwise.
 *
 */
PHP_APCU_API apc_cache_entry_t* apc_cache_find(apc_cache_t* cache, zend_string *key, time_t t);

/*
 * apc_cache_fetch fetches an entry from the cache directly into dst
 *
 */
PHP_APCU_API zend_bool apc_cache_fetch(apc_cache_t* cache, zend_string *key, time_t t, zval *dst);

/*
 * apc_cache_exists searches for a cache entry by its hashed identifier,
 * and returns whether the entry exists.
 */
PHP_APCU_API zend_bool apc_cache_exists(apc_cache_t* cache, zend_string *key, time_t t);

/*
 * apc_cache_delete and apc_cache_delete finds an entry in the cache and deletes it.
 */
PHP_APCU_API zend_bool apc_cache_delete(apc_cache_t* cache, zend_string *key);

/* apc_cache_fetch_zval copies a cache entry value to be usable at runtime.
 */
PHP_APCU_API zend_bool apc_cache_entry_fetch_zval(
		apc_cache_t *cache, apc_cache_entry_t *entry, zval *dst);

/*
 * apc_cache_entry_release decrements the reference count associated with a cache
 * entry. Calling apc_cache_find automatically increments the reference count,
 * and this function must be called post-execution to return the count to its
 * original value. Failing to do so will prevent the entry from being
 * garbage-collected.
 *
 * entry is the cache entry whose ref count you want to decrement.
 */
PHP_APCU_API void apc_cache_entry_release(apc_cache_t *cache, apc_cache_entry_t *entry);

/*
 fetches information about the cache provided for userland status functions
*/
PHP_APCU_API zend_bool apc_cache_info(zval *info, apc_cache_t *cache, zend_bool limited);

/*
 fetches information about the key provided
*/
PHP_APCU_API void apc_cache_stat(apc_cache_t *cache, zend_string *key, zval *stat);

/*
* apc_cache_defense: guard against slamming a key
*  will return true if the following conditions are met:
*	the key provided has a matching hash and length to the last key inserted into cache
*   the last key has a different owner
* in ZTS mode, TSRM determines owner
* in non-ZTS mode, PID determines owner
* Note: this function sets the owner of key during execution
*/
PHP_APCU_API zend_bool apc_cache_defense(apc_cache_t *cache, zend_string *key, time_t t);

/*
* apc_cache_serializer
* sets the serializer for a cache, and by proxy contexts created for the cache
* Note: this avoids race conditions between third party serializers and APCu
*/
PHP_APCU_API void apc_cache_serializer(apc_cache_t* cache, const char* name);

/*
* The remaining functions allow a third party to reimplement expunge
*
* Look at the source of apc_cache_default_expunge for what is expected of this function
*
* The default behaviour of expunge is explained below, should no combination of those options
* be suitable, you will need to reimplement apc_cache_default_expunge and pass it to your
* call to apc_sma_api_impl, this will replace the default functionality.
* The functions below you can use during your own implementation of expunge to gain more
* control over how the expunge process works ...
*
* Note: beware of locking (copy it exactly), setting states is also important
*/

/* {{{ apc_cache_default_expunge
* Where smart is not set:
*  Where no ttl is set on cache:
*   1) Perform cleanup of stale entries
*   2) Expunge if available memory is less than sma->size/2
*  Where ttl is set on cache:
*   1) Perform cleanup of stale entries
*   2) If available memory if less than the size requested, run full expunge
*
* Where smart is set:
*  Where no ttl is set on cache:
*   1) Perform cleanup of stale entries
*   2) Expunge is available memory is less than size * smart
*  Where ttl is set on cache:
*   1) Perform cleanup of stale entries
*   2) If available memory if less than the size requested, run full expunge
*
* The TTL of an entry takes precedence over the TTL of a cache
*/
PHP_APCU_API void apc_cache_default_expunge(apc_cache_t* cache, size_t size);

/*
* apc_cache_entry: generate and create or fetch an entry
*
* @see https://github.com/krakjoe/apcu/issues/142
*/
PHP_APCU_API void apc_cache_entry(apc_cache_t *cache, zend_string *key, zend_fcall_info *fci, zend_fcall_info_cache *fcc, zend_long ttl, zend_long now, zval *return_value);

/* apcu_entry() holds a write lock on the cache while executing user code.
 * That code may call other apcu_* functions, which also try to acquire a
 * read or write lock, which would deadlock. As such, don't try to acquire a
 * lock if the current thread is inside apcu_entry().
 *
 * Whether the current thread is inside apcu_entry() is tracked by APCG(entry_level).
 * This breaks the self-contained apc_cache_t abstraction, but is currently
 * necessary because the entry_level needs to be tracked per-thread, while
 * apc_cache_t is a per-process structure.
 */

static inline zend_bool apc_cache_wlock(apc_cache_t *cache) {
	if (!APCG(entry_level)) {
		return WLOCK(&cache->header->lock);
	}
	return 1;
}

static inline void apc_cache_wunlock(apc_cache_t *cache) {
	if (!APCG(entry_level)) {
		WUNLOCK(&cache->header->lock);
	}
}

static inline zend_bool apc_cache_rlock(apc_cache_t *cache) {
	if (!APCG(entry_level)) {
		return RLOCK(&cache->header->lock);
	}
	return 1;
}

static inline void apc_cache_runlock(apc_cache_t *cache) {
	if (!APCG(entry_level)) {
		RUNLOCK(&cache->header->lock);
	}
}

#endif

/*
 * Local variables:
 * tab-width: 4
 * c-basic-offset: 4
 * End:
 * vim>600: noexpandtab sw=4 ts=4 sts=4 fdm=marker
 * vim<600: noexpandtab sw=4 ts=4 sts=4
 */
apcu-5.1.23/apc_globals.h0000664000175000017500000000706414523735540014146 0ustar  nikicnikic/*
  +----------------------------------------------------------------------+
  | APC                                                                  |
  +----------------------------------------------------------------------+
  | Copyright (c) 2006-2011 The PHP Group                                |
  +----------------------------------------------------------------------+
  | This source file is subject to version 3.01 of the PHP 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.php.net/license/3_01.txt.                                 |
  | If you did not receive a copy of the PHP license and are unable to   |
  | obtain it through the world-wide-web, please send a note to          |
  | license@php.net so we can mail you a copy immediately.               |
  +----------------------------------------------------------------------+
  | Authors: Daniel Cowgill               |
  |          George Schlossnagle                      |
  |          Rasmus Lerdorf                              |
  |          Arun C. Murthy                         |
  |          Gopal Vijayaraghavan                  |
  +----------------------------------------------------------------------+

   This software was contributed to PHP by Community Connect Inc. in 2002
   and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1.
   Future revisions and derivatives of this source code must acknowledge
   Community Connect Inc. as the original contributor of this module by
   leaving this note intact in the source code.

   All other licensing and usage conditions are those of the PHP Group.

 */

#ifndef APC_GLOBALS_H
#define APC_GLOBALS_H

#include "apc.h"

ZEND_BEGIN_MODULE_GLOBALS(apcu)
	/* configuration parameters */
	zend_bool enabled;      /* if true, apc is enabled (defaults to true) */
	zend_long shm_segments;      /* number of shared memory segments to use */
	zend_long shm_size;          /* size of each shared memory segment (in MB) */
	zend_long entries_hint;      /* hint at the number of entries expected */
	zend_long gc_ttl;            /* parameter to apc_cache_create */
	zend_long ttl;               /* parameter to apc_cache_create */
	zend_long smart;             /* smart value */

#if APC_MMAP
	char *mmap_file_mask;   /* mktemp-style file-mask to pass to mmap */
#endif

	/* module variables */
	zend_bool initialized;       /* true if module was initialized */
	zend_bool enable_cli;        /* Flag to override turning APC off for CLI */
	zend_bool slam_defense;      /* true for user cache slam defense */

	char *preload_path;          /* preload path */
	zend_bool coredump_unmap;    /* trap signals that coredump and unmap shared memory */
	zend_bool use_request_time;  /* use the SAPI request start time for TTL */
	time_t request_time;         /* cached request time */

	char *serializer_name;       /* the serializer config option */

	/* Nesting level of apcu_entry calls. */
	unsigned int entry_level;
ZEND_END_MODULE_GLOBALS(apcu)

/* (the following is defined in php_apc.c) */
ZEND_EXTERN_MODULE_GLOBALS(apcu)

#ifdef ZTS
# define APCG(v) TSRMG(apcu_globals_id, zend_apcu_globals *, v)
#else
# define APCG(v) (apcu_globals.v)
#endif

extern struct _apc_cache_t* apc_user_cache;

#endif

/*
 * Local variables:
 * tab-width: 4
 * c-basic-offset: 4
 * End:
 * vim>600: noexpandtab sw=4 ts=4 sts=4 fdm=marker
 * vim<600: noexpandtab sw=4 ts=4 sts=4
 */
apcu-5.1.23/apc.h0000664000175000017500000001337614523735540012446 0ustar  nikicnikic/*
  +----------------------------------------------------------------------+
  | APC                                                                  |
  +----------------------------------------------------------------------+
  | Copyright (c) 2006-2011 The PHP Group                                |
  +----------------------------------------------------------------------+
  | This source file is subject to version 3.01 of the PHP 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.php.net/license/3_01.txt                                  |
  | If you did not receive a copy of the PHP license and are unable to   |
  | obtain it through the world-wide-web, please send a note to          |
  | license@php.net so we can mail you a copy immediately.               |
  +----------------------------------------------------------------------+
  | Authors: Daniel Cowgill               |
  |          George Schlossnagle                      |
  |          Rasmus Lerdorf                              |
  |          Arun C. Murthy                         |
  |          Gopal Vijayaraghavan                  |
  +----------------------------------------------------------------------+

   This software was contributed to PHP by Community Connect Inc. in 2002
   and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1.
   Future revisions and derivatives of this source code must acknowledge
   Community Connect Inc. as the original contributor of this module by
   leaving this note intact in the source code.

   All other licensing and usage conditions are those of the PHP Group.

 */

#ifndef APC_H
#define APC_H

/*
 * This module defines utilities and helper functions used elsewhere in APC.
 */
#ifdef PHP_WIN32
# define PHP_APCU_API __declspec(dllexport)
#elif defined(__GNUC__) && __GNUC__ >= 4
# define PHP_APCU_API __attribute__ ((visibility("default")))
#else
# define PHP_APCU_API
#endif

/* Commonly needed C library headers. */
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

/* UNIX headers (needed for struct stat) */
#include 
#include 
#ifndef PHP_WIN32
#include 
#endif

#ifdef HAVE_CONFIG_H
#include 
#endif

#include "php.h"
#include "main/php_streams.h"

/* console display functions */
PHP_APCU_API void apc_error(const char *format, ...) ZEND_ATTRIBUTE_FORMAT(printf, 1, 2);
PHP_APCU_API void apc_warning(const char *format, ...) ZEND_ATTRIBUTE_FORMAT(printf, 1, 2);
PHP_APCU_API void apc_notice(const char *format, ...) ZEND_ATTRIBUTE_FORMAT(printf, 1, 2);
PHP_APCU_API void apc_debug(const char *format, ...) ZEND_ATTRIBUTE_FORMAT(printf, 1, 2);

/* apc_flip_hash flips keys and values for faster searching */
PHP_APCU_API HashTable* apc_flip_hash(HashTable *hash);

#if defined(__GNUC__)
# define APC_UNUSED __attribute__((unused))
# define APC_USED __attribute__((used))
# define APC_ALLOC __attribute__((malloc))
# if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__  > 2)
#  define APC_HOTSPOT __attribute__((hot))
# else
#  define APC_HOTSPOT
# endif
#else
# define APC_UNUSED
# define APC_USED
# define APC_ALLOC
# define APC_HOTSPOT
#endif

/*
* Serializer API
*/
#define APC_SERIALIZER_ABI "0"
#define APC_SERIALIZER_CONSTANT "\000apc_register_serializer-" APC_SERIALIZER_ABI

#define APC_SERIALIZER_NAME(module) module##_apc_serializer
#define APC_UNSERIALIZER_NAME(module) module##_apc_unserializer

#define APC_SERIALIZER_ARGS unsigned char **buf, size_t *buf_len, const zval *value, void *config
#define APC_UNSERIALIZER_ARGS zval *value, unsigned char *buf, size_t buf_len, void *config

typedef int (*apc_serialize_t)(APC_SERIALIZER_ARGS);
typedef int (*apc_unserialize_t)(APC_UNSERIALIZER_ARGS);

/* {{{ struct definition: apc_serializer_t */
typedef struct apc_serializer_t {
	const char*        name;
	apc_serialize_t    serialize;
	apc_unserialize_t  unserialize;
	void*              config;
} apc_serializer_t;
/* }}} */

/* {{{ _apc_register_serializer
 registers the serializer using the given name and parameters */
PHP_APCU_API int _apc_register_serializer(
        const char* name, apc_serialize_t serialize, apc_unserialize_t unserialize, void *config);
/* }}} */

/* {{{ apc_get_serializers
 fetches the list of serializers */
PHP_APCU_API apc_serializer_t* apc_get_serializers(void); /* }}} */

/* {{{ apc_find_serializer
 finds a previously registered serializer by name */
PHP_APCU_API apc_serializer_t* apc_find_serializer(const char* name); /* }}} */

/* {{{ default serializers */
PHP_APCU_API int APC_SERIALIZER_NAME(php) (APC_SERIALIZER_ARGS);
PHP_APCU_API int APC_UNSERIALIZER_NAME(php) (APC_UNSERIALIZER_ARGS); /* }}} */

#define php_apc_try                        \
{                                          \
	JMP_BUF *zb = EG(bailout);             \
	JMP_BUF ab;                            \
	zend_bool _bailout = 0;                \
	                                       \
	EG(bailout) = &ab;                     \
	if (SETJMP(ab) == SUCCESS) {

#define php_apc_finally                    \
	} else {                               \
		_bailout = 1;                      \
	}

#define php_apc_end_try()                  \
	EG(bailout) = zb;                      \
	if (_bailout) {                        \
		zend_bailout();                    \
	}                                      \
}

#define php_apc_try_finish() (EG(bailout) = zb)

#endif

/*
 * Local variables:
 * tab-width: 4
 * c-basic-offset: 4
 * End:
 * vim>600: noexpandtab sw=4 ts=4 sts=4 fdm=marker
 * vim<600: noexpandtab sw=4 ts=4 sts=4
 */
apcu-5.1.23/apc_iterator.c0000664000175000017500000004016014523735540014341 0ustar  nikicnikic/*
  +----------------------------------------------------------------------+
  | APC                                                                  |
  +----------------------------------------------------------------------+
  | Copyright (c) 2006-2011 The PHP Group                                |
  +----------------------------------------------------------------------+
  | This source file is subject to version 3.01 of the PHP 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.php.net/license/3_01.txt                                  |
  | If you did not receive a copy of the PHP license and are unable to   |
  | obtain it through the world-wide-web, please send a note to          |
  | license@php.net so we can mail you a copy immediately.               |
  +----------------------------------------------------------------------+
  | Authors: Brian Shire                                  |
  +----------------------------------------------------------------------+

 */

#include "php_apc.h"
#include "apc_iterator.h"
#include "apc_cache.h"
#include "apc_strings.h"
#include "apc_time.h"
#if PHP_VERSION_ID >= 80000
# include "apc_iterator_arginfo.h"
#else
# include "apc_iterator_legacy_arginfo.h"
#endif

#include "ext/standard/md5.h"
#include "SAPI.h"
#include "zend_interfaces.h"

static zend_class_entry *apc_iterator_ce;
zend_object_handlers apc_iterator_object_handlers;

zend_class_entry* apc_iterator_get_ce(void) {
	return apc_iterator_ce;
}

#define ENSURE_INITIALIZED(iterator) \
	if (!(iterator)->initialized) { \
		zend_throw_error(NULL, "Trying to use uninitialized APCUIterator"); \
		return; \
	}

/* {{{ apc_iterator_item */
static apc_iterator_item_t* apc_iterator_item_ctor(
		apc_iterator_t *iterator, apc_cache_entry_t *entry) {
	zval zv;
	HashTable *ht;
	apc_iterator_item_t *item = ecalloc(1, sizeof(apc_iterator_item_t));

	array_init(&item->value);
	ht = Z_ARRVAL(item->value);

	item->key = zend_string_dup(entry->key, 0);

	if (APC_ITER_TYPE & iterator->format) {
		ZVAL_STR_COPY(&zv, apc_str_user);
		zend_hash_add_new(ht, apc_str_type, &zv);
	}

	if (APC_ITER_KEY & iterator->format) {
		ZVAL_STR_COPY(&zv, item->key);
		zend_hash_add_new(ht, apc_str_key, &zv);
	}

	if (APC_ITER_VALUE & iterator->format) {
		ZVAL_UNDEF(&zv);
		apc_cache_entry_fetch_zval(apc_user_cache, entry, &zv);
		zend_hash_add_new(ht, apc_str_value, &zv);
	}

	if (APC_ITER_NUM_HITS & iterator->format) {
		ZVAL_LONG(&zv, entry->nhits);
		zend_hash_add_new(ht, apc_str_num_hits, &zv);
	}
	if (APC_ITER_MTIME & iterator->format) {
		ZVAL_LONG(&zv, entry->mtime);
		zend_hash_add_new(ht, apc_str_mtime, &zv);
	}
	if (APC_ITER_CTIME & iterator->format) {
		ZVAL_LONG(&zv, entry->ctime);
		zend_hash_add_new(ht, apc_str_creation_time, &zv);
	}
	if (APC_ITER_DTIME & iterator->format) {
		ZVAL_LONG(&zv, entry->dtime);
		zend_hash_add_new(ht, apc_str_deletion_time, &zv);
	}
	if (APC_ITER_ATIME & iterator->format) {
		ZVAL_LONG(&zv, entry->atime);
		zend_hash_add_new(ht, apc_str_access_time, &zv);
	}
	if (APC_ITER_REFCOUNT & iterator->format) {
		ZVAL_LONG(&zv, entry->ref_count);
		zend_hash_add_new(ht, apc_str_ref_count, &zv);
	}
	if (APC_ITER_MEM_SIZE & iterator->format) {
		ZVAL_LONG(&zv, entry->mem_size);
		zend_hash_add_new(ht, apc_str_mem_size, &zv);
	}
	if (APC_ITER_TTL & iterator->format) {
		ZVAL_LONG(&zv, entry->ttl);
		zend_hash_add_new(ht, apc_str_ttl, &zv);
	}

	return item;
}
/* }}} */

/* {{{ apc_iterator_item_dtor */
static void apc_iterator_item_dtor(apc_iterator_item_t *item) {
	zend_string_release(item->key);
	zval_ptr_dtor(&item->value);
	efree(item);
}
/* }}} */

/* {{{ acp_iterator_free */
static void apc_iterator_free(zend_object *object) {
	apc_iterator_t *iterator = apc_iterator_fetch_from(object);

	if (iterator->initialized == 0) {
		zend_object_std_dtor(object);
		return;
	}

	while (apc_stack_size(iterator->stack) > 0) {
		apc_iterator_item_dtor(apc_stack_pop(iterator->stack));
	}

	apc_stack_destroy(iterator->stack);

	if (iterator->regex) {
		zend_string_release(iterator->regex);
#if PHP_VERSION_ID >= 70300
		pcre2_match_data_free(iterator->re_match_data);
#endif
	}

	if (iterator->search_hash) {
		zend_hash_destroy(iterator->search_hash);
		efree(iterator->search_hash);
	}
	iterator->initialized = 0;

	zend_object_std_dtor(object);
}
/* }}} */

/* {{{ apc_iterator_create */
zend_object* apc_iterator_create(zend_class_entry *ce) {
	apc_iterator_t *iterator =
		(apc_iterator_t*) emalloc(sizeof(apc_iterator_t) + zend_object_properties_size(ce));

	zend_object_std_init(&iterator->obj, ce);
	object_properties_init(&iterator->obj, ce);

	iterator->initialized = 0;
	iterator->stack = NULL;
	iterator->regex = NULL;
	iterator->search_hash = NULL;
	iterator->obj.handlers = &apc_iterator_object_handlers;

	return &iterator->obj;
}
/* }}} */

/* {{{ apc_iterator_search_match
 *       Verify if the key matches our search parameters
 */
static int apc_iterator_search_match(apc_iterator_t *iterator, apc_cache_entry_t *entry) {
	int rval = 1;

	if (iterator->regex) {
#if PHP_VERSION_ID >= 70300
		rval = pcre2_match(
			php_pcre_pce_re(iterator->pce),
			(PCRE2_SPTR) ZSTR_VAL(entry->key), ZSTR_LEN(entry->key),
			0, 0, iterator->re_match_data, php_pcre_mctx()) >= 0;
#else
		rval = pcre_exec(
			iterator->pce->re, iterator->pce->extra,
			ZSTR_VAL(entry->key), ZSTR_LEN(entry->key),
			0, 0, NULL, 0) >= 0;
#endif
	}

	if (iterator->search_hash) {
		rval = zend_hash_exists(iterator->search_hash, entry->key);
	}

	return rval;
}
/* }}} */

/* {{{ apc_iterator_check_expiry */
static int apc_iterator_check_expiry(apc_cache_t* cache, apc_cache_entry_t *entry, time_t t)
{
	if (entry->ttl) {
		if ((time_t) (entry->ctime + entry->ttl) < t) {
			return 0;
		}
	}

	return 1;
}
/* }}} */

/* {{{ apc_iterator_fetch_active */
static size_t apc_iterator_fetch_active(apc_iterator_t *iterator) {
	size_t count = 0;
	apc_iterator_item_t *item;
	time_t t = apc_time();

	while (apc_stack_size(iterator->stack) > 0) {
		apc_iterator_item_dtor(apc_stack_pop(iterator->stack));
	}

	if (!apc_cache_rlock(apc_user_cache)) {
		return count;
	}

	php_apc_try {
		while (count <= iterator->chunk_size && iterator->slot_idx < apc_user_cache->nslots) {
			apc_cache_entry_t *entry = apc_user_cache->slots[iterator->slot_idx];
			while (entry) {
				if (apc_iterator_check_expiry(apc_user_cache, entry, t)) {
					if (apc_iterator_search_match(iterator, entry)) {
						count++;
						item = apc_iterator_item_ctor(iterator, entry);
						if (item) {
							apc_stack_push(iterator->stack, item);
						}
					}
				}
				entry = entry->next;
			}
			iterator->slot_idx++;
		}
	} php_apc_finally {
		iterator->stack_idx = 0;
		apc_cache_runlock(apc_user_cache);
	} php_apc_end_try();

	return count;
}
/* }}} */

/* {{{ apc_iterator_fetch_deleted */
static size_t apc_iterator_fetch_deleted(apc_iterator_t *iterator) {
	size_t count = 0;
	apc_iterator_item_t *item;

	if (!apc_cache_rlock(apc_user_cache)) {
		return count;
	}

	php_apc_try {
		apc_cache_entry_t *entry = apc_user_cache->header->gc;
		while (entry && count <= iterator->slot_idx) {
			count++;
			entry = entry->next;
		}
		count = 0;
		while (entry && count < iterator->chunk_size) {
			if (apc_iterator_search_match(iterator, entry)) {
				count++;
				item = apc_iterator_item_ctor(iterator, entry);
				if (item) {
					apc_stack_push(iterator->stack, item);
				}
			}
			entry = entry->next;
		}
	} php_apc_finally {
		iterator->slot_idx += count;
		iterator->stack_idx = 0;
		apc_cache_runlock(apc_user_cache);
	} php_apc_end_try();

	return count;
}
/* }}} */

/* {{{ apc_iterator_totals */
static void apc_iterator_totals(apc_iterator_t *iterator) {
	time_t t = apc_time();

	if (!apc_cache_rlock(apc_user_cache)) {
		return;
	}

	php_apc_try {
		size_t i;

		for (i=0; i < apc_user_cache->nslots; i++) {
			apc_cache_entry_t *entry = apc_user_cache->slots[i];
			while (entry) {
				if (apc_iterator_check_expiry(apc_user_cache, entry, t)) {
					if (apc_iterator_search_match(iterator, entry)) {
						iterator->size += entry->mem_size;
						iterator->hits += entry->nhits;
						iterator->count++;
					}
				}
				entry = entry->next;
			}
		}
	} php_apc_finally {
		iterator->totals_flag = 1;
		apc_cache_runlock(apc_user_cache);
	} php_apc_end_try();
}
/* }}} */

void apc_iterator_obj_init(apc_iterator_t *iterator, zval *search, zend_long format, size_t chunk_size, zend_long list)
{
	if (!APCG(enabled)) {
		zend_throw_error(NULL, "APC must be enabled to use APCUIterator");
		return;
	}

	if (format > APC_ITER_ALL) {
		apc_error("APCUIterator format is invalid");
		return;
	}

	if (list == APC_LIST_ACTIVE) {
		iterator->fetch = apc_iterator_fetch_active;
	} else if (list == APC_LIST_DELETED) {
		iterator->fetch = apc_iterator_fetch_deleted;
	} else {
		apc_warning("APCUIterator invalid list type");
		return;
	}

	iterator->slot_idx = 0;
	iterator->stack_idx = 0;
	iterator->key_idx = 0;
	iterator->chunk_size = chunk_size == 0 ? APC_DEFAULT_CHUNK_SIZE : chunk_size;
	iterator->stack = apc_stack_create(chunk_size);
	iterator->format = format;
	iterator->totals_flag = 0;
	iterator->count = 0;
	iterator->size = 0;
	iterator->hits = 0;
	iterator->regex = NULL;
	iterator->search_hash = NULL;
	if (search && Z_TYPE_P(search) == IS_STRING && Z_STRLEN_P(search)) {
		iterator->regex = zend_string_copy(Z_STR_P(search));
		iterator->pce = pcre_get_compiled_regex_cache(iterator->regex);

		if (!iterator->pce) {
			apc_error("Could not compile regular expression: %s", Z_STRVAL_P(search));
			zend_string_release(iterator->regex);
			iterator->regex = NULL;
		}

#if PHP_VERSION_ID >= 70300
		iterator->re_match_data = pcre2_match_data_create_from_pattern(
			php_pcre_pce_re(iterator->pce), php_pcre_gctx());
#endif
	} else if (search && Z_TYPE_P(search) == IS_ARRAY) {
		iterator->search_hash = apc_flip_hash(Z_ARRVAL_P(search));
	}
	iterator->initialized = 1;
}

PHP_METHOD(APCUIterator, __construct) {
	apc_iterator_t *iterator = apc_iterator_fetch(getThis());
	zend_long format = APC_ITER_ALL;
	zend_long chunk_size = 0;
	zval *search = NULL;
	zend_long list = APC_LIST_ACTIVE;

	ZEND_PARSE_PARAMETERS_START(0, 4)
		Z_PARAM_OPTIONAL
		Z_PARAM_ZVAL_EX(search, 1, 0)
		Z_PARAM_LONG(format)
		Z_PARAM_LONG(chunk_size)
		Z_PARAM_LONG(list)
	ZEND_PARSE_PARAMETERS_END();

	if (chunk_size < 0) {
		apc_error("APCUIterator chunk size must be 0 or greater");
		return;
	}

	apc_iterator_obj_init(iterator, search, format, chunk_size, list);
}

PHP_METHOD(APCUIterator, rewind) {
	apc_iterator_t *iterator = apc_iterator_fetch(getThis());

	if (zend_parse_parameters_none() == FAILURE) {
		return;
	}

	ENSURE_INITIALIZED(iterator);

	iterator->slot_idx = 0;
	iterator->stack_idx = 0;
	iterator->key_idx = 0;
	iterator->fetch(iterator);
}

PHP_METHOD(APCUIterator, valid) {
	apc_iterator_t *iterator = apc_iterator_fetch(getThis());

	if (zend_parse_parameters_none() == FAILURE) {
		return;
	}

	ENSURE_INITIALIZED(iterator);

	if (apc_stack_size(iterator->stack) == iterator->stack_idx) {
		iterator->fetch(iterator);
	}

	RETURN_BOOL(apc_stack_size(iterator->stack) == 0 ? 0 : 1);
}

PHP_METHOD(APCUIterator, current) {
	apc_iterator_item_t *item;
	apc_iterator_t *iterator = apc_iterator_fetch(getThis());

	if (zend_parse_parameters_none() == FAILURE) {
		return;
	}

	ENSURE_INITIALIZED(iterator);

	if (apc_stack_size(iterator->stack) == iterator->stack_idx) {
		if (iterator->fetch(iterator) == 0) {
			zend_throw_error(NULL, "Cannot call current() on invalid iterator");
			return;
		}
	}

	item = apc_stack_get(iterator->stack, iterator->stack_idx);
	ZVAL_COPY(return_value, &item->value);
}

PHP_METHOD(APCUIterator, key) {
	apc_iterator_item_t *item;
	apc_iterator_t *iterator = apc_iterator_fetch(getThis());

	if (zend_parse_parameters_none() == FAILURE) {
		return;
	}

	ENSURE_INITIALIZED(iterator);
	if (apc_stack_size(iterator->stack) == iterator->stack_idx) {
		if (iterator->fetch(iterator) == 0) {
			zend_throw_error(NULL, "Cannot call key() on invalid iterator");
			return;
		}
	}

	item = apc_stack_get(iterator->stack, iterator->stack_idx);

	if (item->key) {
		RETURN_STR_COPY(item->key);
	} else {
		RETURN_LONG(iterator->key_idx);
	}
}

PHP_METHOD(APCUIterator, next) {
	apc_iterator_t *iterator = apc_iterator_fetch(getThis());

	if (zend_parse_parameters_none() == FAILURE) {
		return;
	}

	ENSURE_INITIALIZED(iterator);
	if (apc_stack_size(iterator->stack) == 0) {
		return;
	}

	iterator->stack_idx++;
	iterator->key_idx++;
}

PHP_METHOD(APCUIterator, getTotalHits) {
	apc_iterator_t *iterator = apc_iterator_fetch(getThis());

	if (zend_parse_parameters_none() == FAILURE) {
		return;
	}

	ENSURE_INITIALIZED(iterator);

	if (iterator->totals_flag == 0) {
		apc_iterator_totals(iterator);
	}

	RETURN_LONG(iterator->hits);
}
/* }}} */

PHP_METHOD(APCUIterator, getTotalSize) {
	apc_iterator_t *iterator = apc_iterator_fetch(getThis());

	if (zend_parse_parameters_none() == FAILURE) {
		return;
	}

	ENSURE_INITIALIZED(iterator);

	if (iterator->totals_flag == 0) {
		apc_iterator_totals(iterator);
	}

	RETURN_LONG(iterator->size);
}

PHP_METHOD(APCUIterator, getTotalCount) {
	apc_iterator_t *iterator = apc_iterator_fetch(getThis());

	if (zend_parse_parameters_none() == FAILURE) {
		return;
	}

	ENSURE_INITIALIZED(iterator);

	if (iterator->totals_flag == 0) {
		apc_iterator_totals(iterator);
	}

	RETURN_LONG(iterator->count);
}

/* {{{ apc_iterator_init */
int apc_iterator_init(int module_number) {
	zend_class_entry ce;

	INIT_CLASS_ENTRY(ce, "APCUIterator", class_APCUIterator_methods);
	apc_iterator_ce = zend_register_internal_class(&ce);
	apc_iterator_ce->create_object = apc_iterator_create;
	zend_class_implements(apc_iterator_ce, 1, zend_ce_iterator);

	REGISTER_LONG_CONSTANT("APC_LIST_ACTIVE", APC_LIST_ACTIVE, CONST_PERSISTENT | CONST_CS);
	REGISTER_LONG_CONSTANT("APC_LIST_DELETED", APC_LIST_DELETED, CONST_PERSISTENT | CONST_CS);
	REGISTER_LONG_CONSTANT("APC_ITER_TYPE", APC_ITER_TYPE, CONST_PERSISTENT | CONST_CS);
	REGISTER_LONG_CONSTANT("APC_ITER_KEY", APC_ITER_KEY, CONST_PERSISTENT | CONST_CS);
	REGISTER_LONG_CONSTANT("APC_ITER_VALUE", APC_ITER_VALUE, CONST_PERSISTENT | CONST_CS);
	REGISTER_LONG_CONSTANT("APC_ITER_NUM_HITS", APC_ITER_NUM_HITS, CONST_PERSISTENT | CONST_CS);
	REGISTER_LONG_CONSTANT("APC_ITER_MTIME", APC_ITER_MTIME, CONST_PERSISTENT | CONST_CS);
	REGISTER_LONG_CONSTANT("APC_ITER_CTIME", APC_ITER_CTIME, CONST_PERSISTENT | CONST_CS);
	REGISTER_LONG_CONSTANT("APC_ITER_DTIME", APC_ITER_DTIME, CONST_PERSISTENT | CONST_CS);
	REGISTER_LONG_CONSTANT("APC_ITER_ATIME", APC_ITER_ATIME, CONST_PERSISTENT | CONST_CS);
	REGISTER_LONG_CONSTANT("APC_ITER_REFCOUNT", APC_ITER_REFCOUNT, CONST_PERSISTENT | CONST_CS);
	REGISTER_LONG_CONSTANT("APC_ITER_MEM_SIZE", APC_ITER_MEM_SIZE, CONST_PERSISTENT | CONST_CS);
	REGISTER_LONG_CONSTANT("APC_ITER_TTL", APC_ITER_TTL, CONST_PERSISTENT | CONST_CS);
	REGISTER_LONG_CONSTANT("APC_ITER_NONE", APC_ITER_NONE, CONST_PERSISTENT | CONST_CS);
	REGISTER_LONG_CONSTANT("APC_ITER_ALL", APC_ITER_ALL, CONST_PERSISTENT | CONST_CS);

	memcpy(&apc_iterator_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));

	apc_iterator_object_handlers.clone_obj = NULL;
	apc_iterator_object_handlers.free_obj = apc_iterator_free;
	apc_iterator_object_handlers.offset = XtOffsetOf(apc_iterator_t, obj);

	return SUCCESS;
}
/* }}} */

int apc_iterator_shutdown(int module_number) {
	return SUCCESS;
}

/* {{{ apc_iterator_delete */
int apc_iterator_delete(zval *zobj) {
	apc_iterator_t *iterator;
	zend_class_entry *ce = Z_OBJCE_P(zobj);
	apc_iterator_item_t *item;

	if (!ce || !instanceof_function(ce, apc_iterator_ce)) {
		apc_error("apc_delete object argument must be instance of APCUIterator.");
		return 0;
	}
	iterator = apc_iterator_fetch(zobj);

	if (iterator->initialized == 0) {
		zend_throw_error(NULL, "Trying to use uninitialized APCUIterator");
		return 0;
	}

	while (iterator->fetch(iterator)) {
		while (iterator->stack_idx < apc_stack_size(iterator->stack)) {
			item = apc_stack_get(iterator->stack, iterator->stack_idx++);
			apc_cache_delete(
				apc_user_cache, item->key);
		}
	}

	return 1;
}
/* }}} */


/*
 * Local variables:
 * tab-width: 4
 * c-basic-offset: 4
 * End:
 * vim>600: noexpandtab sw=4 ts=4 sts=4 fdm=marker
 * vim<600: noexpandtab sw=4 ts=4 sts=4
 */
apcu-5.1.23/apc_iterator.h0000664000175000017500000000744614523735540014360 0ustar  nikicnikic/*
  +----------------------------------------------------------------------+
  | APC                                                                  |
  +----------------------------------------------------------------------+
  | Copyright (c) 2006-2011 The PHP Group                                |
  +----------------------------------------------------------------------+
  | This source file is subject to version 3.01 of the PHP 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.php.net/license/3_01.txt                                  |
  | If you did not receive a copy of the PHP license and are unable to   |
  | obtain it through the world-wide-web, please send a note to          |
  | license@php.net so we can mail you a copy immediately.               |
  +----------------------------------------------------------------------+
  | Authors: Brian Shire                                 |
  +----------------------------------------------------------------------+

 */

#ifndef APC_ITERATOR_H
#define APC_ITERATOR_H

#include "apc.h"
#include "apc_stack.h"

#include "ext/pcre/php_pcre.h"
#include "zend_smart_str.h"

#define APC_DEFAULT_CHUNK_SIZE 100

#define APC_LIST_ACTIVE   0x1
#define APC_LIST_DELETED  0x2

#define APC_ITER_TYPE		(1 << 0)
#define APC_ITER_KEY        (1 << 1)
#define APC_ITER_VALUE      (1 << 2)
#define APC_ITER_NUM_HITS   (1 << 3)
#define APC_ITER_MTIME      (1 << 4)
#define APC_ITER_CTIME      (1 << 5)
#define APC_ITER_DTIME      (1 << 6)
#define APC_ITER_ATIME      (1 << 7)
#define APC_ITER_REFCOUNT   (1 << 8)
#define APC_ITER_MEM_SIZE   (1 << 9)
#define APC_ITER_TTL        (1 << 10)

#define APC_ITER_NONE       0
#define APC_ITER_ALL        (0xffffffffL)

/* {{{ apc_iterator_t */
typedef struct _apc_iterator_t {
	short int initialized;   /* sanity check in case __construct failed */
	zend_long format;             /* format bitmask of the return values ie: key, value, info */
	size_t (*fetch)(struct _apc_iterator_t *iterator);
							 /* fetch callback to fetch items from cache slots or lists */
	size_t slot_idx;           /* index to the slot array or linked list */
	size_t chunk_size;         /* number of entries to pull down per fetch */
	apc_stack_t *stack;      /* stack of entries pulled from cache */
	int stack_idx;           /* index into the current stack */
	pcre_cache_entry *pce;     /* regex filter on entry identifiers */
#if PHP_VERSION_ID >= 70300
	pcre2_match_data *re_match_data; /* match data for regex */
#endif
	zend_string *regex;
	HashTable *search_hash;  /* hash of keys to iterate over */
	zend_long key_idx;            /* incrementing index for numerical keys */
	short int totals_flag;   /* flag if totals have been calculated */
	zend_long hits;               /* hit total */
	size_t size;             /* size total */
	zend_long count;              /* count total */
	zend_object obj;
} apc_iterator_t;
/* }}} */

#define apc_iterator_fetch_from(o) ((apc_iterator_t*)((char*)o - XtOffsetOf(apc_iterator_t, obj)))
#define apc_iterator_fetch(z) apc_iterator_fetch_from(Z_OBJ_P(z))

/* {{{ apc_iterator_item */
typedef struct _apc_iterator_item_t {
	zend_string *key;
	zval value;
} apc_iterator_item_t;
/* }}} */

PHP_APCU_API void apc_iterator_obj_init(
	apc_iterator_t *iterator,
	zval *search,
	zend_long format,
	size_t chunk_size,
	zend_long list);
PHP_APCU_API zend_class_entry* apc_iterator_get_ce(void);
PHP_APCU_API int apc_iterator_init(int module_number);
PHP_APCU_API int apc_iterator_shutdown(int module_number);

extern int apc_iterator_delete(zval *key);
#endif

/*
 * Local variables:
 * tab-width: 4
 * c-basic-offset: 4
 * End:
 * vim>600: noexpandtab sw=4 ts=4 sts=4 fdm=marker
 * vim<600: noexpandtab sw=4 ts=4 sts=4
 */
apcu-5.1.23/apc_iterator.stub.php0000664000175000017500000000117314523735540015663 0ustar  nikicnikic                        |
  +----------------------------------------------------------------------+
 */

#ifndef HAVE_APC_LOCK_H
# include "apc_lock.h"
#endif

/*
 * While locking calls should never fail, apcu checks for the success of write-lock
 * acquisitions, to prevent more damage when a deadlock is detected.
 */

#ifdef PHP_WIN32
PHP_APCU_API zend_bool apc_lock_init() {
	return 1;
}

PHP_APCU_API void apc_lock_cleanup() {
}

PHP_APCU_API zend_bool apc_lock_create(apc_lock_t *lock) {
	return NULL != apc_windows_cs_create(lock);
}

static inline zend_bool apc_lock_rlock_impl(apc_lock_t *lock) {
	apc_windows_cs_rdlock(lock);
	return 1;
}

static inline zend_bool apc_lock_wlock_impl(apc_lock_t *lock) {
	apc_windows_cs_lock(lock);
	return 1;
}

PHP_APCU_API zend_bool apc_lock_wunlock(apc_lock_t *lock) {
	apc_windows_cs_unlock_wr(lock);
	return 1;
}

PHP_APCU_API zend_bool apc_lock_runlock(apc_lock_t *lock) {
	apc_windows_cs_unlock_rd(lock);
	return 1;
}

PHP_APCU_API void apc_lock_destroy(apc_lock_t *lock) {
	apc_windows_cs_destroy(lock);
}

#elif defined(APC_NATIVE_RWLOCK)

static zend_bool apc_lock_ready = 0;
static pthread_rwlockattr_t apc_lock_attr;

PHP_APCU_API zend_bool apc_lock_init() {
	if (apc_lock_ready) {
		return 1;
	}
	apc_lock_ready = 1;

	if (pthread_rwlockattr_init(&apc_lock_attr) != SUCCESS) {
		return 0;
	}
	if (pthread_rwlockattr_setpshared(&apc_lock_attr, PTHREAD_PROCESS_SHARED) != SUCCESS) {
		return 0;
	}
	return 1;
}

PHP_APCU_API void apc_lock_cleanup() {
	if (!apc_lock_ready) {
		return;
	}
	apc_lock_ready = 0;

	pthread_rwlockattr_destroy(&apc_lock_attr);
}

PHP_APCU_API zend_bool apc_lock_create(apc_lock_t *lock) {
	return pthread_rwlock_init(lock, &apc_lock_attr) == SUCCESS;
}

static inline zend_bool apc_lock_rlock_impl(apc_lock_t *lock) {
	return pthread_rwlock_rdlock(lock) == 0;
}

static inline zend_bool apc_lock_wlock_impl(apc_lock_t *lock) {
	return pthread_rwlock_wrlock(lock) == 0;
}

PHP_APCU_API zend_bool apc_lock_wunlock(apc_lock_t *lock) {
	pthread_rwlock_unlock(lock);
	return 1;
}

PHP_APCU_API zend_bool apc_lock_runlock(apc_lock_t *lock) {
	pthread_rwlock_unlock(lock);
	return 1;
}

PHP_APCU_API void apc_lock_destroy(apc_lock_t *lock) {
	pthread_rwlock_destroy(lock);
}

#elif defined(APC_LOCK_RECURSIVE)

static zend_bool apc_lock_ready = 0;
static pthread_mutexattr_t apc_lock_attr;

PHP_APCU_API zend_bool apc_lock_init() {
	if (apc_lock_ready) {
		return 1;
	}
	apc_lock_ready = 1;

	if (pthread_mutexattr_init(&apc_lock_attr) != SUCCESS) {
		return 0;
	}

	if (pthread_mutexattr_setpshared(&apc_lock_attr, PTHREAD_PROCESS_SHARED) != SUCCESS) {
		return 0;
	}

	pthread_mutexattr_settype(&apc_lock_attr, PTHREAD_MUTEX_RECURSIVE);
	return 1;
}

PHP_APCU_API void apc_lock_cleanup() {
	if (!apc_lock_ready) {
		return;
	}
	apc_lock_ready = 0;

	pthread_mutexattr_destroy(&apc_lock_attr);
}

PHP_APCU_API zend_bool apc_lock_create(apc_lock_t *lock) {
	pthread_mutex_init(lock, &apc_lock_attr);
	return 1;
}

static inline zend_bool apc_lock_rlock_impl(apc_lock_t *lock) {
	return pthread_mutex_lock(lock) == 0;
}

static inline zend_bool apc_lock_wlock_impl(apc_lock_t *lock) {
	return pthread_mutex_lock(lock) == 0;
}

PHP_APCU_API zend_bool apc_lock_wunlock(apc_lock_t *lock) {
	pthread_mutex_unlock(lock);
	return 1;
}

PHP_APCU_API zend_bool apc_lock_runlock(apc_lock_t *lock) {
	pthread_mutex_unlock(lock);
	return 1;
}

PHP_APCU_API void apc_lock_destroy(apc_lock_t *lock) {
	pthread_mutex_destroy(lock);
}

#elif defined(APC_SPIN_LOCK)

static int apc_lock_try(apc_lock_t *lock) {
	int failed = 1;

	asm volatile
	(
		"xchgl %0, 0(%1)" :
		"=r" (failed) : "r" (&lock->state),
		"0" (failed)
	);

	return failed;
}

static int apc_lock_get(apc_lock_t *lock) {
	int failed = 1;

	do {
		failed = apc_lock_try(lock);
#ifdef APC_LOCK_NICE
		usleep(0);
#endif
	} while (failed);

	return failed;
}

static int apc_lock_release(apc_lock_t *lock) {
	int released = 0;

	asm volatile (
		"xchg %0, 0(%1)" : "=r" (released) : "r" (&lock->state),
		"0" (released)
	);

	return !released;
}

PHP_APCU_API zend_bool apc_lock_init() {
	return 0;
}

PHP_APCU_API void apc_lock_cleanup() {
}

PHP_APCU_API zend_bool apc_lock_create(apc_lock_t *lock) {
	lock->state = 0;
}

static inline zend_bool apc_lock_rlock_impl(apc_lock_t *lock) {
	apc_lock_get(lock);
	return 1;
}

static inline zend_bool apc_lock_wlock_impl(apc_lock_t *lock) {
	apc_lock_get(lock);
	return 1;
}

PHP_APCU_API zend_bool apc_lock_wunlock(apc_lock_t *lock) {
	apc_lock_release(lock);
	return 1;
}

PHP_APCU_API zend_bool apc_lock_runlock(apc_lock_t *lock) {
	apc_lock_release(lock);
	return 1;
}

PHP_APCU_API void apc_lock_destroy(apc_lock_t *lock) {
}

#else

#include 
#include 

static int apc_fcntl_call(int fd, int cmd, int type, off_t offset, int whence, off_t len) {
	int ret;
	struct flock lock;

	lock.l_type = type;
	lock.l_start = offset;
	lock.l_whence = whence;
	lock.l_len = len;
	lock.l_pid = 0;

	do {
		ret = fcntl(fd, cmd, &lock) ;
	} while(ret < 0 && errno == EINTR);

	return(ret);
}

PHP_APCU_API zend_bool apc_lock_init() {
	return 0;
}

PHP_APCU_API void apc_lock_cleanup() {
}

PHP_APCU_API zend_bool apc_lock_create(apc_lock_t *lock) {
	char lock_path[] = "/tmp/.apc.XXXXXX";

	*lock = mkstemp(lock_path);
	if (*lock > 0) {
		unlink(lock_path);
		return 1;
	} else {
		return 0;
	}
}

static inline zend_bool apc_lock_rlock_impl(apc_lock_t *lock) {
	apc_fcntl_call((*lock), F_SETLKW, F_RDLCK, 0, SEEK_SET, 0);
	return 1;
}

static inline zend_bool apc_lock_wlock_impl(apc_lock_t *lock) {
	apc_fcntl_call((*lock), F_SETLKW, F_WRLCK, 0, SEEK_SET, 0);
	return 1;
}

PHP_APCU_API zend_bool apc_lock_wunlock(apc_lock_t *lock) {
	apc_fcntl_call((*lock), F_SETLKW, F_UNLCK, 0, SEEK_SET, 0);
	return 1;
}

PHP_APCU_API zend_bool apc_lock_runlock(apc_lock_t *lock) {
	apc_fcntl_call((*lock), F_SETLKW, F_UNLCK, 0, SEEK_SET, 0);
	return 1;
}

PHP_APCU_API void apc_lock_destroy(apc_lock_t *lock) {
	close(*lock);
}

#endif

/* Shared for all lock implementations */

PHP_APCU_API zend_bool apc_lock_wlock(apc_lock_t *lock) {
	HANDLE_BLOCK_INTERRUPTIONS();
	if (apc_lock_wlock_impl(lock)) {
		return 1;
	}

	HANDLE_UNBLOCK_INTERRUPTIONS();
	apc_warning("Failed to acquire write lock");
	return 0;
}

PHP_APCU_API zend_bool apc_lock_rlock(apc_lock_t *lock) {
	HANDLE_BLOCK_INTERRUPTIONS();
	if (apc_lock_rlock_impl(lock)) {
		return 1;
	}

	HANDLE_UNBLOCK_INTERRUPTIONS();
	apc_warning("Failed to acquire read lock");
	return 0;
}
apcu-5.1.23/apc_lock.h0000664000175000017500000001052114523735540013443 0ustar  nikicnikic/*
  +----------------------------------------------------------------------+
  | APCu                                                                 |
  +----------------------------------------------------------------------+
  | Copyright (c) 2013 The PHP Group                                |
  +----------------------------------------------------------------------+
  | This source file is subject to version 3.01 of the PHP 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.php.net/license/3_01.txt                                  |
  | If you did not receive a copy of the PHP license and are unable to   |
  | obtain it through the world-wide-web, please send a note to          |
  | license@php.net so we can mail you a copy immediately.               |
  +----------------------------------------------------------------------+
  | Author: Joe Watkins                         |
  +----------------------------------------------------------------------+
 */

#ifndef APC_LOCK_H
#define APC_LOCK_H

/*
 APCu works most efficiently where there is access to native read/write locks
 If the current system has native rwlocks present they will be used, if they are
	not present, APCu will emulate their behavior with standard mutex.
 While APCu is emulating read/write locks, reads and writes are exclusive,
	additionally the write lock prefers readers, as is the default behaviour of
	the majority of Posix rwlock implementations
*/

#ifdef HAVE_CONFIG_H
# include 
#endif

#include "apc.h"

#ifndef PHP_WIN32
# ifndef __USE_UNIX98
#  define __USE_UNIX98
# endif
# include "pthread.h"
# ifndef APC_SPIN_LOCK
#   ifndef APC_FCNTL_LOCK
#       ifdef APC_NATIVE_RWLOCK
		typedef pthread_rwlock_t apc_lock_t;
#		define APC_LOCK_SHARED
#       else
		typedef pthread_mutex_t apc_lock_t;
#		define APC_LOCK_RECURSIVE
#       endif
#   else
		typedef int apc_lock_t;
#		define APC_LOCK_FILE
#   endif
# else
# define APC_LOCK_NICE 1
typedef struct {
	unsigned long state;
} apc_lock_t;
# endif
#else
/* XXX kernel lock mode only for now, compatible through all the wins, add more ifdefs for others */
# include "apc_windows_srwlock_kernel.h"
typedef apc_windows_cs_rwlock_t apc_lock_t;
# define APC_LOCK_SHARED
#endif

/* {{{ functions */
/*
  The following functions should be called once per process:
	apc_lock_init initializes attributes suitable for all locks
	apc_lock_cleanup destroys those attributes
  This saves us from having to create and destroy attributes for
  every lock we use at runtime */
PHP_APCU_API zend_bool apc_lock_init(void);
PHP_APCU_API void      apc_lock_cleanup(void);
/*
  The following functions should be self explanitory:
*/
PHP_APCU_API zend_bool apc_lock_create(apc_lock_t *lock);
PHP_APCU_API zend_bool apc_lock_rlock(apc_lock_t *lock);
PHP_APCU_API zend_bool apc_lock_wlock(apc_lock_t *lock);
PHP_APCU_API zend_bool apc_lock_runlock(apc_lock_t *lock);
PHP_APCU_API zend_bool apc_lock_wunlock(apc_lock_t *lock);
PHP_APCU_API void apc_lock_destroy(apc_lock_t *lock); /* }}} */

/* {{{ generic locking macros */
#define CREATE_LOCK(lock)     apc_lock_create(lock)
#define DESTROY_LOCK(lock)    apc_lock_destroy(lock)
#define WLOCK(lock)           apc_lock_wlock(lock)
#define WUNLOCK(lock)         { apc_lock_wunlock(lock); HANDLE_UNBLOCK_INTERRUPTIONS(); }
#define RLOCK(lock)           apc_lock_rlock(lock)
#define RUNLOCK(lock)         { apc_lock_runlock(lock); HANDLE_UNBLOCK_INTERRUPTIONS(); }
/* }}} */

/* atomic operations */
#ifdef PHP_WIN32
# ifdef _WIN64
#  define ATOMIC_INC(a) InterlockedIncrement64(&a)
#  define ATOMIC_DEC(a) InterlockedDecrement64(&a)
#  define ATOMIC_ADD(a, b) (InterlockedExchangeAdd64(&a, b) + b)
#  define ATOMIC_CAS(a, old, new) (InterlockedCompareExchange64(&a, new, old) == old)
# else
#  define ATOMIC_INC(a) InterlockedIncrement(&a)
#  define ATOMIC_DEC(a) InterlockedDecrement(&a)
#  define ATOMIC_ADD(a, b) (InterlockedExchangeAdd(&a, b) + b)
#  define ATOMIC_CAS(a, old, new) (InterlockedCompareExchange(&a, new, old) == old)
# endif
#else
# define ATOMIC_INC(a) __sync_add_and_fetch(&a, 1)
# define ATOMIC_DEC(a) __sync_sub_and_fetch(&a, 1)
# define ATOMIC_ADD(a, b) __sync_add_and_fetch(&a, b)
# define ATOMIC_CAS(a, old, new) __sync_bool_compare_and_swap(&a, old, new)
#endif

#endif
apcu-5.1.23/apc_mmap.c0000664000175000017500000001064114523735540013443 0ustar  nikicnikic/*
  +----------------------------------------------------------------------+
  | APC                                                                  |
  +----------------------------------------------------------------------+
  | Copyright (c) 2006-2011 The PHP Group                                |
  +----------------------------------------------------------------------+
  | This source file is subject to version 3.01 of the PHP 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.php.net/license/3_01.txt                                  |
  | If you did not receive a copy of the PHP license and are unable to   |
  | obtain it through the world-wide-web, please send a note to          |
  | license@php.net so we can mail you a copy immediately.               |
  +----------------------------------------------------------------------+
  | Authors: Rasmus Lerdorf                              |
  +----------------------------------------------------------------------+

   This software was contributed to PHP by Community Connect Inc. in 2002
   and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1.
   Future revisions and derivatives of this source code must acknowledge
   Community Connect Inc. as the original contributor of this module by
   leaving this note intact in the source code.

   All other licensing and usage conditions are those of the PHP Group.

 */

#include "apc.h"
#include "apc_mmap.h"
#include "apc_lock.h"

#if APC_MMAP

#include 
#include 
#include 

/*
 * Some operating systems (like FreeBSD) have a MAP_NOSYNC flag that
 * tells whatever update daemons might be running to not flush dirty
 * vm pages to disk unless absolutely necessary.  My guess is that
 * most systems that don't have this probably default to only synching
 * to disk when absolutely necessary.
 */
#ifndef MAP_NOSYNC
#define MAP_NOSYNC 0
#endif

/* support for systems where MAP_ANONYMOUS is defined but not MAP_ANON, ie: HP-UX bug #14615 */
#if !defined(MAP_ANON) && defined(MAP_ANONYMOUS)
# define MAP_ANON MAP_ANONYMOUS
#endif

apc_segment_t apc_mmap(char *file_mask, size_t size)
{
	apc_segment_t segment;

	int fd = -1;
	int flags = MAP_SHARED | MAP_NOSYNC;
#ifdef APC_MEMPROTECT
	int remap = 1;
#endif

	/* If no filename was provided, do an anonymous mmap */
	if(!file_mask || (file_mask && !strlen(file_mask))) {
#if !defined(MAP_ANON)
		zend_error_noreturn(E_CORE_ERROR, "Anonymous mmap does not appear to be available on this system (MAP_ANON/MAP_ANONYMOUS).  Please see the apc.mmap_file_mask INI option.");
#else
		fd = -1;
		flags = MAP_SHARED | MAP_ANON;
#ifdef APC_MEMPROTECT
		remap = 0;
#endif
#endif
	} else if(!strcmp(file_mask,"/dev/zero")) {
		fd = open("/dev/zero", O_RDWR, S_IRUSR | S_IWUSR);
		if(fd == -1) {
			zend_error_noreturn(E_CORE_ERROR, "apc_mmap: open on /dev/zero failed");
		}
#ifdef APC_MEMPROTECT
		remap = 0; /* cannot remap */
#endif
	} else {
		/*
		 * Otherwise we do a normal filesystem mmap
		 */
		fd = mkstemp(file_mask);
		if(fd == -1) {
			zend_error_noreturn(E_CORE_ERROR, "apc_mmap: mkstemp on %s failed", file_mask);
		}
		if (ftruncate(fd, size) < 0) {
			close(fd);
			unlink(file_mask);
			zend_error_noreturn(E_CORE_ERROR, "apc_mmap: ftruncate failed");
		}
		unlink(file_mask);
	}

	segment.shmaddr = (void *)mmap(NULL, size, PROT_READ | PROT_WRITE, flags, fd, 0);
	segment.size = size;

#ifdef APC_MEMPROTECT
	if(remap) {
		segment.roaddr = (void *)mmap(NULL, size, PROT_READ, flags, fd, 0);
	} else {
		segment.roaddr = NULL;
	}
#endif

	if ((long)segment.shmaddr == -1) {
		zend_error_noreturn(E_CORE_ERROR, "apc_mmap: Failed to mmap %zu bytes. Is your apc.shm_size too large?", size);
	}

#ifdef MADV_HUGEPAGE
	/* enable transparent huge pages to reduce TLB misses (Linux
	   only) */
	madvise(segment.shmaddr, size, MADV_HUGEPAGE);
#endif

	if (fd != -1) close(fd);

	return segment;
}

void apc_unmap(apc_segment_t *segment)
{
	if (munmap(segment->shmaddr, segment->size) < 0) {
		apc_warning("apc_unmap: munmap failed");
	}

#ifdef APC_MEMPROTECT
	if (segment->roaddr && munmap(segment->roaddr, segment->size) < 0) {
		apc_warning("apc_unmap: munmap failed");
	}
#endif

}

#endif

/*
 * Local variables:
 * tab-width: 4
 * c-basic-offset: 4
 * End:
 * vim>600: noexpandtab sw=4 ts=4 sts=4 fdm=marker
 * vim<600: noexpandtab sw=4 ts=4 sts=4
 */
apcu-5.1.23/apc_mmap.h0000664000175000017500000000367614523735540013462 0ustar  nikicnikic/*
  +----------------------------------------------------------------------+
  | APC                                                                  |
  +----------------------------------------------------------------------+
  | Copyright (c) 2006-2011 The PHP Group                                |
  +----------------------------------------------------------------------+
  | This source file is subject to version 3.01 of the PHP 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.php.net/license/3_01.txt                                  |
  | If you did not receive a copy of the PHP license and are unable to   |
  | obtain it through the world-wide-web, please send a note to          |
  | license@php.net so we can mail you a copy immediately.               |
  +----------------------------------------------------------------------+
  | Authors: Gopal V                                     |
  +----------------------------------------------------------------------+

   This software was contributed to PHP by Community Connect Inc. in 2002
   and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1.
   Future revisions and derivatives of this source code must acknowledge
   Community Connect Inc. as the original contributor of this module by
   leaving this note intact in the source code.

   All other licensing and usage conditions are those of the PHP Group.

 */

#ifndef APC_MMAP_H
#define APC_MMAP_H

#include 

#include "apc.h"
#include "apc_sma.h"

/* Wrapper functions for shared memory mapped files */

#if APC_MMAP
apc_segment_t apc_mmap(char *file_mask, size_t size);
void apc_unmap(apc_segment_t* segment);
#endif

#endif

/*
 * Local variables:
 * tab-width: 4
 * c-basic-offset: 4
 * End:
 * vim>600: noexpandtab sw=4 ts=4 sts=4 fdm=marker
 * vim<600: noexpandtab sw=4 ts=4 sts=4
 */
apcu-5.1.23/apc_mutex.c0000664000175000017500000000436614523735540013662 0ustar  nikicnikic/*
  +----------------------------------------------------------------------+
  | APCu                                                                 |
  +----------------------------------------------------------------------+
  | Copyright (c) 2013 The PHP Group                                |
  +----------------------------------------------------------------------+
  | This source file is subject to version 3.01 of the PHP 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.php.net/license/3_01.txt                                  |
  | If you did not receive a copy of the PHP license and are unable to   |
  | obtain it through the world-wide-web, please send a note to          |
  | license@php.net so we can mail you a copy immediately.               |
  +----------------------------------------------------------------------+
  | Author: Fabian Franz                              |
  +----------------------------------------------------------------------+
 */
#include "apc_mutex.h"

#ifdef APC_HAS_PTHREAD_MUTEX

static zend_bool apc_mutex_ready = 0;
static pthread_mutexattr_t apc_mutex_attr;

PHP_APCU_API zend_bool apc_mutex_init() {
	if (apc_mutex_ready) {
		return 1;
	}
	apc_mutex_ready = 1;

	if (pthread_mutexattr_init(&apc_mutex_attr) != SUCCESS) {
		return 0;
	}

	if (pthread_mutexattr_setpshared(&apc_mutex_attr, PTHREAD_PROCESS_SHARED) != SUCCESS) {
		return 0;
	}

	return 1;
}

PHP_APCU_API void apc_mutex_cleanup() {
	if (!apc_mutex_ready) {
		return;
	}
	apc_mutex_ready = 0;

	pthread_mutexattr_destroy(&apc_mutex_attr);
}

PHP_APCU_API zend_bool apc_mutex_create(apc_mutex_t *lock) {
	pthread_mutex_init(lock, &apc_mutex_attr);
	return 1;
}

PHP_APCU_API zend_bool apc_mutex_lock(apc_mutex_t *lock) {
	HANDLE_BLOCK_INTERRUPTIONS();
	if (pthread_mutex_lock(lock) == 0) {
		return 1;
	}

	HANDLE_UNBLOCK_INTERRUPTIONS();
	apc_warning("Failed to acquire lock");
	return 0;
}

PHP_APCU_API zend_bool apc_mutex_unlock(apc_mutex_t *lock) {
	pthread_mutex_unlock(lock);
	HANDLE_UNBLOCK_INTERRUPTIONS();
	return 1;
}

PHP_APCU_API void apc_mutex_destroy(apc_mutex_t *lock) {
	pthread_mutex_destroy(lock);
}

#endif
apcu-5.1.23/apc_mutex.h0000664000175000017500000000436614523735540013667 0ustar  nikicnikic/*
  +----------------------------------------------------------------------+
  | APCu                                                                 |
  +----------------------------------------------------------------------+
  | Copyright (c) 2013 The PHP Group                                |
  +----------------------------------------------------------------------+
  | This source file is subject to version 3.01 of the PHP 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.php.net/license/3_01.txt                                  |
  | If you did not receive a copy of the PHP license and are unable to   |
  | obtain it through the world-wide-web, please send a note to          |
  | license@php.net so we can mail you a copy immediately.               |
  +----------------------------------------------------------------------+
  | Author: Joe Watkins                         |
  +----------------------------------------------------------------------+
 */

#ifndef APC_MUTEX_H
#define APC_MUTEX_H

#include "apc.h"

#ifdef APC_HAS_PTHREAD_MUTEX

#include "pthread.h"

typedef pthread_mutex_t apc_mutex_t;

PHP_APCU_API zend_bool apc_mutex_init(void);
PHP_APCU_API void apc_mutex_cleanup(void);
PHP_APCU_API zend_bool apc_mutex_create(apc_mutex_t *lock);
PHP_APCU_API zend_bool apc_mutex_lock(apc_mutex_t *lock);
PHP_APCU_API zend_bool apc_mutex_unlock(apc_mutex_t *lock);
PHP_APCU_API void apc_mutex_destroy(apc_mutex_t *lock);

#define APC_MUTEX_INIT()          apc_mutex_init()
#define APC_MUTEX_CLEANUP()       apc_mutex_cleanup()

#define APC_CREATE_MUTEX(lock)    apc_mutex_create(lock)
#define APC_DESTROY_MUTEX(lock)   apc_mutex_destroy(lock)
#define APC_MUTEX_LOCK(lock)      apc_mutex_lock(lock)
#define APC_MUTEX_UNLOCK(lock)    apc_mutex_unlock(lock)

#else

#include "apc_lock.h"

typedef apc_lock_t apc_mutex_t;

// Fallback to normal locks

#define APC_MUTEX_INIT()
#define APC_MUTEX_CLEANUP()

#define APC_CREATE_MUTEX(lock)    CREATE_LOCK(lock)
#define APC_DESTROY_MUTEX(lock)   DESTROY_LOCK(lock)
#define APC_MUTEX_LOCK(lock)      WLOCK(lock)
#define APC_MUTEX_UNLOCK(lock)    WUNLOCK(lock)

#endif

#endif
apcu-5.1.23/apc_persist.c0000664000175000017500000004745214523735540014214 0ustar  nikicnikic/*
  +----------------------------------------------------------------------+
  | APCu                                                                 |
  +----------------------------------------------------------------------+
  | Copyright (c) 2018 The PHP Group                                     |
  +----------------------------------------------------------------------+
  | This source file is subject to version 3.01 of the PHP 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.php.net/license/3_01.txt                                  |
  | If you did not receive a copy of the PHP license and are unable to   |
  | obtain it through the world-wide-web, please send a note to          |
  | license@php.net so we can mail you a copy immediately.               |
  +----------------------------------------------------------------------+
  | Author: Nikita Popov                                  |
  +----------------------------------------------------------------------+
 */

#include "apc.h"
#include "apc_cache.h"

#if PHP_VERSION_ID < 70300
# define GC_SET_REFCOUNT(ref, rc) (GC_REFCOUNT(ref) = (rc))
# define GC_ADDREF(ref) GC_REFCOUNT(ref)++
# define GC_SET_PERSISTENT_TYPE(ref, type) (GC_TYPE_INFO(ref) = type)
# if PHP_VERSION_ID < 70200
#  define GC_ARRAY IS_ARRAY
# else
#  define GC_ARRAY (IS_ARRAY | (GC_COLLECTABLE << GC_FLAGS_SHIFT))
# endif
#else
# define GC_SET_PERSISTENT_TYPE(ref, type) \
	(GC_TYPE_INFO(ref) = type | (GC_PERSISTENT << GC_FLAGS_SHIFT))
#endif

#if PHP_VERSION_ID < 80000
# define GC_REFERENCE IS_REFERENCE
#endif

/*
 * PERSIST: Copy from request memory to SHM.
 */

typedef struct _apc_persist_context_t {
	/* Serializer to use */
	apc_serializer_t *serializer;
	/* Computed size of the needed SMA allocation */
	size_t size;
	/* Whether or not we may have to memoize refcounted addresses */
	zend_bool memoization_needed;
	/* Whether to serialize the top-level value */
	zend_bool use_serialization;
	/* Serialized object/array string, in case there can only be one */
	unsigned char *serialized_str;
	size_t serialized_str_len;
	/* Whole SMA allocation */
	char *alloc;
	/* Current position in allocation */
	char *alloc_cur;
	/* HashTable storing refcounteds for which the size has already been counted. */
	HashTable already_counted;
	/* HashTable storing already allocated refcounteds. Pointers to refcounteds are stored. */
	HashTable already_allocated;
} apc_persist_context_t;

#define ADD_SIZE(sz) ctxt->size += ZEND_MM_ALIGNED_SIZE(sz)
#define ADD_SIZE_STR(len) ADD_SIZE(_ZSTR_STRUCT_SIZE(len))

#define ALLOC(sz) apc_persist_alloc(ctxt, sz)
#define COPY(val, sz) apc_persist_alloc_copy(ctxt, val, sz)

static zend_bool apc_persist_calc_zval(apc_persist_context_t *ctxt, const zval *zv);
static void apc_persist_copy_zval_impl(apc_persist_context_t *ctxt, zval *zv);

/* Used to reduce hash collisions when using pointers in hash tables. (#175) */
static inline zend_ulong apc_shr3(zend_ulong index) {
	return (index >> 3) | (index << (SIZEOF_ZEND_LONG * 8 - 3));
}

static inline void apc_persist_copy_zval(apc_persist_context_t *ctxt, zval *zv) {
	/* No data apart from the zval itself */
	if (Z_TYPE_P(zv) < IS_STRING) {
		return;
	}

	apc_persist_copy_zval_impl(ctxt, zv);
}

void apc_persist_init_context(apc_persist_context_t *ctxt, apc_serializer_t *serializer) {
	ctxt->serializer = serializer;
	ctxt->size = 0;
	ctxt->memoization_needed = 0;
	ctxt->use_serialization = 0;
	ctxt->serialized_str = NULL;
	ctxt->serialized_str_len = 0;
	ctxt->alloc = NULL;
	ctxt->alloc_cur = NULL;
}

void apc_persist_destroy_context(apc_persist_context_t *ctxt) {
	if (ctxt->memoization_needed) {
		zend_hash_destroy(&ctxt->already_counted);
		zend_hash_destroy(&ctxt->already_allocated);
	}
	if (ctxt->serialized_str) {
		efree(ctxt->serialized_str);
	}
}

static zend_bool apc_persist_calc_memoize(apc_persist_context_t *ctxt, void *ptr) {
	zval tmp;
	zend_ulong key;
	if (!ctxt->memoization_needed) {
		return 0;
	}

	key = apc_shr3((zend_ulong)(uintptr_t) ptr);
	if (zend_hash_index_exists(&ctxt->already_counted, key)) {
		return 1;
	}

	ZVAL_NULL(&tmp);
	zend_hash_index_add_new(&ctxt->already_counted, key, &tmp);
	return 0;
}

static zend_bool apc_persist_calc_ht(apc_persist_context_t *ctxt, const HashTable *ht) {
	uint32_t idx;

	/* In php 7.3+, this points to the immutable zend_empty_array outside of shared memory. */
	if (ht->nNumOfElements == 0) {
#if PHP_VERSION_ID < 70300
		ADD_SIZE(sizeof(HashTable));
#endif
		return 1;
	}
	ADD_SIZE(sizeof(HashTable));

	/* TODO Too sparse hashtables could be compacted here */
#if PHP_VERSION_ID >= 80200
	if (HT_IS_PACKED(ht)) {
		ADD_SIZE(HT_PACKED_USED_SIZE(ht));
		for (idx = 0; idx < ht->nNumUsed; idx++) {
			zval *val = ht->arPacked + idx;
			ZEND_ASSERT(Z_TYPE_P(val) != IS_INDIRECT && "INDIRECT in packed array?");
			if (!apc_persist_calc_zval(ctxt, val)) {
				return 0;
			}
		}
	} else
#endif
	{
		ADD_SIZE(HT_USED_SIZE(ht));
		for (idx = 0; idx < ht->nNumUsed; idx++) {
			Bucket *p = ht->arData + idx;
			if (Z_TYPE(p->val) == IS_UNDEF) continue;

			/* This can only happen if $GLOBALS is placed in the cache.
			 * Don't bother with this edge-case, fall back to serialization. */
			if (Z_TYPE(p->val) == IS_INDIRECT) {
				ctxt->use_serialization = 1;
				return 0;
			}

			/* TODO These strings can be reused
			if (p->key && !apc_persist_calc_is_handled(ctxt, (zend_refcounted *) p->key)) {
				ADD_SIZE_STR(ZSTR_LEN(p->key));
			}*/
			if (p->key) {
				ADD_SIZE_STR(ZSTR_LEN(p->key));
			}
			if (!apc_persist_calc_zval(ctxt, &p->val)) {
				return 0;
			}
		}
	}

	return 1;
}

static zend_bool apc_persist_calc_serialize(apc_persist_context_t *ctxt, const zval *zv) {
	unsigned char *buf = NULL;
	size_t buf_len = 0;

	apc_serialize_t serialize = APC_SERIALIZER_NAME(php);
	void *config = NULL;
	if (ctxt->serializer) {
		serialize = ctxt->serializer->serialize;
		config = ctxt->serializer->config;
	}

	if (!serialize(&buf, &buf_len, zv, config)) {
		return 0;
	}

	/* We only ever serialize the top-level value, memoization cannot be needed */
	ZEND_ASSERT(!ctxt->memoization_needed);
	ctxt->serialized_str = buf;
	ctxt->serialized_str_len = buf_len;

	ADD_SIZE_STR(buf_len);
	return 1;
}

static zend_bool apc_persist_calc_zval(apc_persist_context_t *ctxt, const zval *zv) {
	if (Z_TYPE_P(zv) < IS_STRING) {
		/* No data apart from the zval itself */
		return 1;
	}

	if (ctxt->use_serialization) {
		return apc_persist_calc_serialize(ctxt, zv);
	}

	if (apc_persist_calc_memoize(ctxt, Z_COUNTED_P(zv))) {
		return 1;
	}

	switch (Z_TYPE_P(zv)) {
		case IS_STRING:
			ADD_SIZE_STR(Z_STRLEN_P(zv));
			return 1;
		case IS_ARRAY:
			return apc_persist_calc_ht(ctxt, Z_ARRVAL_P(zv));
		case IS_REFERENCE:
			ADD_SIZE(sizeof(zend_reference));
			return apc_persist_calc_zval(ctxt, Z_REFVAL_P(zv));
		case IS_OBJECT:
			ctxt->use_serialization = 1;
			return 0;
		case IS_RESOURCE:
			apc_warning("Cannot store resources in apcu cache");
			return 0;
		EMPTY_SWITCH_DEFAULT_CASE()
	}
}

static zend_bool apc_persist_calc(apc_persist_context_t *ctxt, const apc_cache_entry_t *entry) {
	ADD_SIZE(sizeof(apc_cache_entry_t));
	ADD_SIZE_STR(ZSTR_LEN(entry->key));
	return apc_persist_calc_zval(ctxt, &entry->val);
}

static inline void *apc_persist_get_already_allocated(apc_persist_context_t *ctxt, void *ptr) {
	if (ctxt->memoization_needed) {
		return zend_hash_index_find_ptr(&ctxt->already_allocated, (uintptr_t) ptr);
	}
	return NULL;
}

static inline void apc_persist_add_already_allocated(
		apc_persist_context_t *ctxt, const void *old_ptr, void *new_ptr) {
	if (ctxt->memoization_needed) {
		zend_hash_index_add_new_ptr(&ctxt->already_allocated, (uintptr_t) old_ptr, new_ptr);
	}
}

static inline void *apc_persist_alloc(apc_persist_context_t *ctxt, size_t size) {
	void *ptr = ctxt->alloc_cur;
	ctxt->alloc_cur += ZEND_MM_ALIGNED_SIZE(size);
	ZEND_ASSERT(ctxt->alloc_cur <= ctxt->alloc + ctxt->size);
	return ptr;
}

static inline void *apc_persist_alloc_copy(
		apc_persist_context_t *ctxt, const void *val, size_t size) {
	void *ptr = apc_persist_alloc(ctxt, size);
	memcpy(ptr, val, size);
	return ptr;
}

static zend_string *apc_persist_copy_cstr(
		apc_persist_context_t *ctxt, const char *orig_buf, size_t buf_len, zend_ulong hash) {
	zend_string *str = ALLOC(_ZSTR_STRUCT_SIZE(buf_len));

	GC_SET_REFCOUNT(str, 1);
	GC_SET_PERSISTENT_TYPE(str, IS_STRING);

	ZSTR_H(str) = hash;
	ZSTR_LEN(str) = buf_len;
	memcpy(ZSTR_VAL(str), orig_buf, buf_len);
	ZSTR_VAL(str)[buf_len] = '\0';
	zend_string_hash_val(str);

	return str;
}

static zend_string *apc_persist_copy_zstr_no_add(
		apc_persist_context_t *ctxt, const zend_string *orig_str) {
	return apc_persist_copy_cstr(
		ctxt, ZSTR_VAL(orig_str), ZSTR_LEN(orig_str), ZSTR_H(orig_str));
}

static inline zend_string *apc_persist_copy_zstr(
		apc_persist_context_t *ctxt, const zend_string *orig_str) {
	zend_string *str = apc_persist_copy_zstr_no_add(ctxt, orig_str);
	apc_persist_add_already_allocated(ctxt, orig_str, str);
	return str;
}

static zend_reference *apc_persist_copy_ref(
		apc_persist_context_t *ctxt, const zend_reference *orig_ref) {
	zend_reference *ref = ALLOC(sizeof(zend_reference));
	apc_persist_add_already_allocated(ctxt, orig_ref, ref);

	GC_SET_REFCOUNT(ref, 1);
	GC_SET_PERSISTENT_TYPE(ref, GC_REFERENCE);
#if PHP_VERSION_ID >= 70400
	ref->sources.ptr = NULL;
#endif

	ZVAL_COPY_VALUE(&ref->val, &orig_ref->val);
	apc_persist_copy_zval(ctxt, &ref->val);

	return ref;
}

static const uint32_t uninitialized_bucket[-HT_MIN_MASK] = {HT_INVALID_IDX, HT_INVALID_IDX};

static zend_array *apc_persist_copy_ht(apc_persist_context_t *ctxt, const HashTable *orig_ht) {
#if PHP_VERSION_ID >= 70300
	if (orig_ht->nNumOfElements == 0) {
		return (HashTable *)&zend_empty_array;
	}
#endif
	HashTable *ht = COPY(orig_ht, sizeof(HashTable));
	uint32_t idx;
	apc_persist_add_already_allocated(ctxt, orig_ht, ht);

	GC_SET_REFCOUNT(ht, 1);
	GC_SET_PERSISTENT_TYPE(ht, GC_ARRAY);

	/* Immutable arrays from opcache may lack a dtor and the apply protection flag. */
	ht->pDestructor = ZVAL_PTR_DTOR;
#if PHP_VERSION_ID < 70300
	ht->u.flags |= HASH_FLAG_APPLY_PROTECTION;
#endif

	ht->u.flags |= HASH_FLAG_STATIC_KEYS;
	if (ht->nNumUsed == 0) {
#if PHP_VERSION_ID >= 70400
		ht->u.flags = HASH_FLAG_UNINITIALIZED;
#else
		ht->u.flags &= ~(HASH_FLAG_INITIALIZED|HASH_FLAG_PACKED);
#endif
		ht->nNextFreeElement = 0;
		ht->nTableMask = HT_MIN_MASK;
		HT_SET_DATA_ADDR(ht, &uninitialized_bucket);
		return ht;
	}

	ht->nNextFreeElement = 0;
	ht->nInternalPointer = HT_INVALID_IDX;
#if PHP_VERSION_ID >= 80200
	if (HT_IS_PACKED(ht)) {
		HT_SET_DATA_ADDR(ht, COPY(HT_GET_DATA_ADDR(ht), HT_PACKED_USED_SIZE(ht)));
		for (idx = 0; idx < ht->nNumUsed; idx++) {
			zval *val = ht->arPacked + idx;
			if (Z_TYPE_P(val) == IS_UNDEF) continue;

			if (ht->nInternalPointer == HT_INVALID_IDX) {
				ht->nInternalPointer = idx;
			}

			if ((zend_long) idx >= (zend_long) ht->nNextFreeElement) {
				ht->nNextFreeElement = idx + 1;
			}

			apc_persist_copy_zval(ctxt, val);
		}
	} else
#endif
	{
		HT_SET_DATA_ADDR(ht, COPY(HT_GET_DATA_ADDR(ht), HT_USED_SIZE(ht)));
		for (idx = 0; idx < ht->nNumUsed; idx++) {
			Bucket *p = ht->arData + idx;
			if (Z_TYPE(p->val) == IS_UNDEF) continue;

			if (ht->nInternalPointer == HT_INVALID_IDX) {
				ht->nInternalPointer = idx;
			}

			if (p->key) {
				p->key = apc_persist_copy_zstr_no_add(ctxt, p->key);
				ht->u.flags &= ~HASH_FLAG_STATIC_KEYS;
			} else if ((zend_long) p->h >= (zend_long) ht->nNextFreeElement) {
				ht->nNextFreeElement = p->h + 1;
			}

			apc_persist_copy_zval(ctxt, &p->val);
		}
	}

	return ht;
}

static void apc_persist_copy_serialize(
		apc_persist_context_t *ctxt, zval *zv) {
	zend_string *str;
	zend_uchar orig_type = Z_TYPE_P(zv);
	ZEND_ASSERT(orig_type == IS_ARRAY || orig_type == IS_OBJECT);

	ZEND_ASSERT(!ctxt->memoization_needed);
	ZEND_ASSERT(ctxt->serialized_str);
	str = apc_persist_copy_cstr(ctxt,
		(char *) ctxt->serialized_str, ctxt->serialized_str_len, 0);

	/* Store as PTR type to distinguish from other strings */
	ZVAL_PTR(zv, str);
}

static void apc_persist_copy_zval_impl(apc_persist_context_t *ctxt, zval *zv) {
	void *ptr;

	if (ctxt->use_serialization) {
		apc_persist_copy_serialize(ctxt, zv);
		return;
	}

	ptr = apc_persist_get_already_allocated(ctxt, Z_COUNTED_P(zv));
	switch (Z_TYPE_P(zv)) {
		case IS_STRING:
			if (!ptr) ptr = apc_persist_copy_zstr(ctxt, Z_STR_P(zv));
			ZVAL_STR(zv, ptr);
			return;
		case IS_ARRAY:
			if (!ptr) ptr = apc_persist_copy_ht(ctxt, Z_ARRVAL_P(zv));
			ZVAL_ARR(zv, ptr);
			return;
		case IS_REFERENCE:
			if (!ptr) ptr = apc_persist_copy_ref(ctxt, Z_REF_P(zv));
			ZVAL_REF(zv, ptr);
			return;
		EMPTY_SWITCH_DEFAULT_CASE()
	}
}

static apc_cache_entry_t *apc_persist_copy(
		apc_persist_context_t *ctxt, const apc_cache_entry_t *orig_entry) {
	apc_cache_entry_t *entry = COPY(orig_entry, sizeof(apc_cache_entry_t));
	entry->key = apc_persist_copy_zstr_no_add(ctxt, entry->key);
	apc_persist_copy_zval(ctxt, &entry->val);
	return entry;
}

apc_cache_entry_t *apc_persist(
		apc_sma_t *sma, apc_serializer_t *serializer, const apc_cache_entry_t *orig_entry) {
	apc_persist_context_t ctxt;
	apc_cache_entry_t *entry;

	apc_persist_init_context(&ctxt, serializer);

	/* The top-level value should never be a reference */
	ZEND_ASSERT(Z_TYPE(orig_entry->val) != IS_REFERENCE);

	/* If we're serializing an array using the default serializer, we will have
	 * to keep track of potentially repeated refcounted structures. */
	if (!serializer && Z_TYPE(orig_entry->val) == IS_ARRAY) {
		ctxt.memoization_needed = 1;
		zend_hash_init(&ctxt.already_counted, 0, NULL, NULL, 0);
		zend_hash_init(&ctxt.already_allocated, 0, NULL, NULL, 0);
	}

	/* Objects are always serialized, and arrays when a serializer is set.
	 * Other cases are detected during apc_persist_calc(). */
	if (Z_TYPE(orig_entry->val) == IS_OBJECT
			|| (serializer && Z_TYPE(orig_entry->val) == IS_ARRAY)) {
		ctxt.use_serialization = 1;
	}

	if (!apc_persist_calc(&ctxt, orig_entry)) {
		if (!ctxt.use_serialization) {
			apc_persist_destroy_context(&ctxt);
			return NULL;
		}

		/* Try again with serialization */
		apc_persist_destroy_context(&ctxt);
		apc_persist_init_context(&ctxt, serializer);
		ctxt.use_serialization = 1;
		if (!apc_persist_calc(&ctxt, orig_entry)) {
			apc_persist_destroy_context(&ctxt);
			return NULL;
		}
	}

	ctxt.alloc = ctxt.alloc_cur = apc_sma_malloc(sma, ctxt.size);
	if (!ctxt.alloc) {
		apc_persist_destroy_context(&ctxt);
		return NULL;
	}

	entry = apc_persist_copy(&ctxt, orig_entry);
	ZEND_ASSERT(ctxt.alloc_cur == ctxt.alloc + ctxt.size);

	entry->mem_size = ctxt.size;

	apc_persist_destroy_context(&ctxt);
	return entry;
}

/*
 * UNPERSIST: Copy from SHM to request memory.
 */

typedef struct _apc_unpersist_context_t {
	/* Whether we need to memoize already copied refcounteds. */
	zend_bool memoization_needed;
	/* HashTable storing already copied refcounteds. */
	HashTable already_copied;
} apc_unpersist_context_t;

static void apc_unpersist_zval_impl(apc_unpersist_context_t *ctxt, zval *zv);

static inline void apc_unpersist_zval(apc_unpersist_context_t *ctxt, zval *zv) {
	/* No data apart from the zval itself */
	if (Z_TYPE_P(zv) < IS_STRING) {
		return;
	}

	apc_unpersist_zval_impl(ctxt, zv);
}

static zend_bool apc_unpersist_serialized(
		zval *dst, zend_string *str, apc_serializer_t *serializer) {
	apc_unserialize_t unserialize = APC_UNSERIALIZER_NAME(php);
	void *config = NULL;

	if (serializer) {
		unserialize = serializer->unserialize;
		config = serializer->config;
	}

	if (unserialize(dst, (unsigned char *) ZSTR_VAL(str), ZSTR_LEN(str), config)) {
		return 1;
	}

	ZVAL_NULL(dst);
	return 0;
}

static inline void *apc_unpersist_get_already_copied(apc_unpersist_context_t *ctxt, void *ptr) {
	if (ctxt->memoization_needed) {
		return zend_hash_index_find_ptr(&ctxt->already_copied, apc_shr3((zend_ulong)(uintptr_t)ptr));
	}
	return NULL;
}

static inline void apc_unpersist_add_already_copied(
		apc_unpersist_context_t *ctxt, const void *old_ptr, void *new_ptr) {
	if (ctxt->memoization_needed) {
		zend_hash_index_add_new_ptr(&ctxt->already_copied, apc_shr3((zend_ulong)(uintptr_t)old_ptr), new_ptr);
	}
}

static zend_string *apc_unpersist_zstr(apc_unpersist_context_t *ctxt, const zend_string *orig_str) {
	zend_string *str = zend_string_init(ZSTR_VAL(orig_str), ZSTR_LEN(orig_str), 0);
	ZSTR_H(str) = ZSTR_H(orig_str);
	apc_unpersist_add_already_copied(ctxt, orig_str, str);
	return str;
}

static zend_reference *apc_unpersist_ref(
		apc_unpersist_context_t *ctxt, const zend_reference *orig_ref) {
	zend_reference *ref = emalloc(sizeof(zend_reference));
	apc_unpersist_add_already_copied(ctxt, orig_ref, ref);

	GC_SET_REFCOUNT(ref, 1);
	GC_TYPE_INFO(ref) = GC_REFERENCE;
#if PHP_VERSION_ID >= 70400
	ref->sources.ptr = NULL;
#endif

	ZVAL_COPY_VALUE(&ref->val, &orig_ref->val);
	apc_unpersist_zval(ctxt, &ref->val);
	return ref;
}

/* Compute the size of the HashTable data to create when unpersisting. */
static zend_always_inline size_t apc_compute_ht_data_size(const HashTable *ht) {
#if PHP_VERSION_ID >= 80200
	if (HT_IS_PACKED(ht)) {
		return HT_PACKED_SIZE(ht);
	}
#endif
	return HT_SIZE(ht);
}

static zend_array *apc_unpersist_ht(
		apc_unpersist_context_t *ctxt, const HashTable *orig_ht) {
	HashTable *ht = emalloc(sizeof(HashTable));

	apc_unpersist_add_already_copied(ctxt, orig_ht, ht);
	memcpy(ht, orig_ht, sizeof(HashTable));
	GC_TYPE_INFO(ht) = GC_ARRAY;
#if PHP_VERSION_ID >= 70300
	/* Caller used ZVAL_EMPTY_ARRAY and set different zval flags instead */
	ZEND_ASSERT(ht->nNumOfElements > 0 && ht->nNumUsed > 0);
#else
	if (ht->nNumUsed == 0) {
		HT_SET_DATA_ADDR(ht, &uninitialized_bucket);
		return ht;
	}
#endif

	HT_SET_DATA_ADDR(ht, emalloc(apc_compute_ht_data_size(ht)));
	memcpy(HT_GET_DATA_ADDR(ht), HT_GET_DATA_ADDR(orig_ht), HT_HASH_SIZE(ht->nTableMask));

#if PHP_VERSION_ID >= 80200
	if (HT_IS_PACKED(ht)) {
		zval *p = ht->arPacked, *q = orig_ht->arPacked, *p_end = p + ht->nNumUsed;
		for (; p < p_end; p++, q++) {
			*p = *q;
			apc_unpersist_zval(ctxt, p);
		}
	} else
#endif
	if (ht->u.flags & HASH_FLAG_STATIC_KEYS) {
		Bucket *p = ht->arData, *q = orig_ht->arData, *p_end = p + ht->nNumUsed;
		for (; p < p_end; p++, q++) {
			/* No need to check for UNDEF, as unpersist_zval can be safely called on UNDEF */
			*p = *q;
			apc_unpersist_zval(ctxt, &p->val);
		}
	} else {
		Bucket *p = ht->arData, *q = orig_ht->arData, *p_end = p + ht->nNumUsed;
		for (; p < p_end; p++, q++) {
			if (Z_TYPE(q->val) == IS_UNDEF) {
				ZVAL_UNDEF(&p->val);
				continue;
			}

			p->val = q->val;
			p->h = q->h;
			if (q->key) {
				p->key = zend_string_dup(q->key, 0);
			} else {
				p->key = NULL;
			}
			apc_unpersist_zval(ctxt, &p->val);
		}
	}

	return ht;
}

static void apc_unpersist_zval_impl(apc_unpersist_context_t *ctxt, zval *zv) {
	void *ptr = apc_unpersist_get_already_copied(ctxt, Z_COUNTED_P(zv));
	if (ptr) {
		Z_COUNTED_P(zv) = ptr;
		Z_ADDREF_P(zv);
		return;
	}

	switch (Z_TYPE_P(zv)) {
		case IS_STRING:
			Z_STR_P(zv) = apc_unpersist_zstr(ctxt, Z_STR_P(zv));
			return;
		case IS_REFERENCE:
			Z_REF_P(zv) = apc_unpersist_ref(ctxt, Z_REF_P(zv));
			return;
		case IS_ARRAY:
#if PHP_VERSION_ID >= 70300
			if (Z_ARR_P(zv)->nNumOfElements == 0) {
				ZVAL_EMPTY_ARRAY(zv); /* #323 */
				return;
			}
#endif
			Z_ARR_P(zv) = apc_unpersist_ht(ctxt, Z_ARR_P(zv));
			return;
		default:
			ZEND_ASSERT(0);
			return;
	}
}

zend_bool apc_unpersist(zval *dst, const zval *value, apc_serializer_t *serializer) {
	apc_unpersist_context_t ctxt;

	if (Z_TYPE_P(value) == IS_PTR) {
		return apc_unpersist_serialized(dst, Z_PTR_P(value), serializer);
	}

	ctxt.memoization_needed = 0;
	ZEND_ASSERT(Z_TYPE_P(value) != IS_REFERENCE);
	if (Z_TYPE_P(value) == IS_ARRAY) {
		ctxt.memoization_needed = 1;
		zend_hash_init(&ctxt.already_copied, 0, NULL, NULL, 0);
	}

	ZVAL_COPY_VALUE(dst, value);
	apc_unpersist_zval(&ctxt, dst);

	if (ctxt.memoization_needed) {
		zend_hash_destroy(&ctxt.already_copied);
	}
	return 1;
}
apcu-5.1.23/apc.php0000664000175000017500000012566014523735540013006 0ustar  nikicnikic                               |
  |          Rasmus Lerdorf                              |
  |          Ilia Alshanetsky                          |
  +----------------------------------------------------------------------+

   All other licensing and usage conditions are those of the PHP Group.

 */

////////// READ OPTIONAL CONFIGURATION FILE ////////////
if (file_exists("apc.conf.php")) include("apc.conf.php");
////////////////////////////////////////////////////////

////////// BEGIN OF DEFAULT CONFIG AREA ///////////////////////////////////////////////////////////

defaults('USE_AUTHENTICATION',1);           // Use (internal) authentication - best choice if
                                            // no other authentication is available
                                            // If set to 0:
                                            //  There will be no further authentication. You
                                            //  will have to handle this by yourself!
                                            // If set to 1:
                                            //  You need to change ADMIN_PASSWORD to make
                                            //  this work!
defaults('ADMIN_USERNAME','apc');           // Admin Username
defaults('ADMIN_PASSWORD','password');      // Admin Password - CHANGE THIS TO ENABLE!!!

// (beckerr) I'm using a clear text password here, because I've no good idea how to let
//           users generate a md5 or crypt password in a easy way to fill it in above

//defaults('DATE_FORMAT', "d.m.Y H:i:s");   // German
defaults('DATE_FORMAT', 'Y/m/d H:i:s');     // US

defaults('GRAPH_SIZE',200);                 // Image size

//defaults('PROXY', 'tcp://127.0.0.1:8080');

////////// END OF DEFAULT CONFIG AREA /////////////////////////////////////////////////////////////


// "define if not defined"
function defaults($d,$v) {
    if (!defined($d)) define($d,$v); // or just @define(...)
}

// rewrite $PHP_SELF to block XSS attacks
//
$PHP_SELF= isset($_SERVER['PHP_SELF']) ? htmlentities(strip_tags($_SERVER['PHP_SELF'],''), ENT_QUOTES, 'UTF-8') : '';
$time = time();
$host = php_uname('n');
if($host) { $host = '('.$host.')'; }
if (isset($_SERVER['SERVER_ADDR'])) {
    $host .= ' ('.$_SERVER['SERVER_ADDR'].')';
}

// operation constants
define('OB_HOST_STATS',1);
define('OB_USER_CACHE',2);
define('OB_VERSION_CHECK',3);

// check validity of input variables
$vardom=array(
    'OB'    => '/^\d+$/',           // operational mode switch
    'CC'    => '/^[01]$/',          // clear cache requested
    'DU'    => '/^.*$/',            // Delete User Key
    'SH'    => '/^[a-z0-9]+$/',     // shared object description

    'IMG'   => '/^[123]$/',         // image to generate
    'LO'    => '/^1$/',             // login requested

    'COUNT' => '/^\d+$/',           // number of line displayed in list
    'SCOPE' => '/^[AD]$/',          // list view scope
    'SORT1' => '/^[AHSMCDTZ]$/',    // first sort key
    'SORT2' => '/^[DA]$/',          // second sort key
    'AGGR'  => '/^\d+$/',           // aggregation by dir level
    'SEARCH'    => '~^[a-zA-Z0-9/_.-]*$~'           // aggregation by dir level
);

// cache scope
$scope_list=array(
    'A' => 'cache_list',
    'D' => 'deleted_list'
);

// handle POST and GET requests
if (empty($_REQUEST)) {
    if (!empty($_GET) && !empty($_POST)) {
        $_REQUEST = array_merge($_GET, $_POST);
    } else if (!empty($_GET)) {
        $_REQUEST = $_GET;
    } else if (!empty($_POST)) {
        $_REQUEST = $_POST;
    } else {
        $_REQUEST = array();
    }
}

// check parameter syntax
foreach($vardom as $var => $dom) {
    if (!isset($_REQUEST[$var])) {
        $MYREQUEST[$var]=null;
    } else if (!is_array($_REQUEST[$var]) && preg_match($dom.'D',$_REQUEST[$var])) {
        $MYREQUEST[$var]=$_REQUEST[$var];
    } else {
        $MYREQUEST[$var]=$_REQUEST[$var]=null;
    }
}

// check parameter semantics
if (empty($MYREQUEST['SCOPE'])) $MYREQUEST['SCOPE']="A";
if (empty($MYREQUEST['SORT1'])) $MYREQUEST['SORT1']="H";
if (empty($MYREQUEST['SORT2'])) $MYREQUEST['SORT2']="D";
if (empty($MYREQUEST['OB']))    $MYREQUEST['OB']=OB_HOST_STATS;
if (!isset($MYREQUEST['COUNT'])) $MYREQUEST['COUNT']=20;
if (!isset($scope_list[$MYREQUEST['SCOPE']])) $MYREQUEST['SCOPE']='A';

$MY_SELF=
    "$PHP_SELF".
    "?SCOPE=".$MYREQUEST['SCOPE'].
    "&SORT1=".$MYREQUEST['SORT1'].
    "&SORT2=".$MYREQUEST['SORT2'].
    "&COUNT=".$MYREQUEST['COUNT'];
$MY_SELF_WO_SORT=
    "$PHP_SELF".
    "?SCOPE=".$MYREQUEST['SCOPE'].
    "&COUNT=".$MYREQUEST['COUNT'];

// authentication needed?
//
if (!USE_AUTHENTICATION) {
    $AUTHENTICATED=1;
} else {
    $AUTHENTICATED=0;
    if (ADMIN_PASSWORD!='password' && ($MYREQUEST['LO'] == 1 || isset($_SERVER['PHP_AUTH_USER']))) {

        if (!isset($_SERVER['PHP_AUTH_USER']) ||
            !isset($_SERVER['PHP_AUTH_PW']) ||
            $_SERVER['PHP_AUTH_USER'] != ADMIN_USERNAME ||
            $_SERVER['PHP_AUTH_PW'] != ADMIN_PASSWORD) {
            Header("WWW-Authenticate: Basic realm=\"APC Login\"");
            Header("HTTP/1.0 401 Unauthorized");

            echo <<
                

Rejected!

Wrong Username or Password!
 
  Continue... EOB; exit; } else { $AUTHENTICATED=1; } } } // clear cache if ($AUTHENTICATED && isset($MYREQUEST['CC']) && $MYREQUEST['CC']) { apcu_clear_cache(); } if ($AUTHENTICATED && !empty($MYREQUEST['DU'])) { apcu_delete($MYREQUEST['DU']); } if(!function_exists('apcu_cache_info')) { echo "No cache info available. APC does not appear to be running."; exit; } $limited = $MYREQUEST['OB'] != OB_USER_CACHE; $cache = apcu_cache_info($limited); $mem=apcu_sma_info(); // don't cache this page // header("Cache-Control: no-store, no-cache, must-revalidate"); // HTTP/1.1 header("Cache-Control: post-check=0, pre-check=0", false); header("Pragma: no-cache"); // HTTP/1.0 function duration($ts) { global $time; $years = (int)((($time - $ts)/(7*86400))/52.177457); $rem = (int)(($time-$ts)-($years * 52.177457 * 7 * 86400)); $weeks = (int)(($rem)/(7*86400)); $days = (int)(($rem)/86400) - $weeks*7; $hours = (int)(($rem)/3600) - $days*24 - $weeks*7*24; $mins = (int)(($rem)/60) - $hours*60 - $days*24*60 - $weeks*7*24*60; $str = ''; if($years==1) $str .= "$years year, "; if($years>1) $str .= "$years years, "; if($weeks==1) $str .= "$weeks week, "; if($weeks>1) $str .= "$weeks weeks, "; if($days==1) $str .= "$days day,"; if($days>1) $str .= "$days days,"; if($hours == 1) $str .= " $hours hour and"; if($hours>1) $str .= " $hours hours and"; if($mins == 1) $str .= " 1 minute"; else $str .= " $mins minutes"; return $str; } // create graphics // function graphics_avail() { return extension_loaded('gd'); } if (isset($MYREQUEST['IMG'])) { if (!graphics_avail()) { exit(0); } function fill_arc($im, $centerX, $centerY, $diameter, $start, $end, $color1,$color2,$text='',$placeindex=0) { $r=$diameter/2; $w=deg2rad(round(360+$start+($end-$start)/2)%360); if (function_exists("imagefilledarc")) { // exists only if GD 2.0.1 is available imagefilledarc($im, $centerX+1, $centerY+1, $diameter, $diameter, round($start), round($end), $color1, IMG_ARC_PIE); imagefilledarc($im, $centerX, $centerY, $diameter, $diameter, round($start), round($end), $color2, IMG_ARC_PIE); imagefilledarc($im, $centerX, $centerY, $diameter, $diameter, round($start), round($end), $color1, IMG_ARC_NOFILL|IMG_ARC_EDGED); } else { imagearc($im, $centerX, $centerY, $diameter, $diameter, round($start), round($end), $color2); imageline($im, $centerX, $centerY, $centerX + round(cos(deg2rad($start)) * $r), $centerY + round(sin(deg2rad($start)) * $r), $color2); imageline($im, $centerX, $centerY, $centerX + round(cos(deg2rad($start+1)) * $r), $centerY + round(sin(deg2rad($start)) * $r), $color2); imageline($im, $centerX, $centerY, $centerX + round(cos(deg2rad($end-1)) * $r), $centerY + round(sin(deg2rad($end)) * $r), $color2); imageline($im, $centerX, $centerY, $centerX + round(cos(deg2rad($end)) * $r), $centerY + round(sin(deg2rad($end)) * $r), $color2); imagefill($im,$centerX + round($r*cos($w)/2), $centerY + round($r*sin($w)/2), $color2); } if ($text) { if ($placeindex>0) { imageline($im,$centerX + round($r*cos($w)/2), $centerY + round($r*sin($w)/2),$diameter, $placeindex*12,$color1); imagestring($im,4,$diameter, $placeindex*12,$text,$color1); } else { imagestring($im,4,$centerX + round($r*cos($w)/2), $centerY + round($r*sin($w)/2),$text,$color1); } } } function text_arc($im, $centerX, $centerY, $diameter, $start, $end, $color1,$text,$placeindex=0) { $r=$diameter/2; $w=deg2rad((360+round($start)+round(($end-$start)/2))%360); if ($placeindex>0) { imageline($im,$centerX + round($r*cos($w)/2), $centerY + round($r*sin($w)/2),$diameter, $placeindex*12,$color1); imagestring($im,4,$diameter, $placeindex*12,$text,$color1); } else { imagestring($im,4,$centerX + round($r*cos($w)/2), $centerY + round($r*sin($w)/2),$text,$color1); } } function fill_box($im, $x, $y, $w, $h, $color1, $color2,$text='',$placeindex='') { global $col_black; $x = round($x); $y = round($y); $w = round($w); $h = round($h); $x1=$x+$w-1; $y1=$y+$h-1; imagerectangle($im, $x, $y1, $x1+1, $y+1, $col_black); if($y1>$y) imagefilledrectangle($im, $x, $y, $x1, $y1, $color2); else imagefilledrectangle($im, $x, $y1, $x1, $y, $color2); imagerectangle($im, $x, $y1, $x1, $y, $color1); if ($text) { if ($placeindex>0) { if ($placeindex<16) { $px=5; $py=$placeindex*12+6; imagefilledrectangle($im, $px+90, $py+3, $px+90-4, $py-3, $color2); imageline($im,$x,$y+round($h/2),$px+90,$py,$color2); imagestring($im,2,$px,$py-6,$text,$color1); } else { if ($placeindex<31) { $px=$x+40*2; $py=($placeindex-15)*12+6; } else { $px=$x+40*2+100*intval(($placeindex-15)/15); $py=($placeindex%15)*12+6; } imagefilledrectangle($im, $px, $py+3, $px-4, $py-3, $color2); imageline($im,$x+$w,$y+round($h/2),$px,$py,$color2); imagestring($im,2,$px+2,$py-6,$text,$color1); } } else { imagestring($im,4,$x+5,$y1-16,$text,$color1); } } } $size = GRAPH_SIZE; // image size if ($MYREQUEST['IMG']==3) $image = imagecreate(2*$size+150, $size+10); else $image = imagecreate($size+50, $size+10); $col_white = imagecolorallocate($image, 0xFF, 0xFF, 0xFF); $col_red = imagecolorallocate($image, 0xD0, 0x60, 0x30); $col_green = imagecolorallocate($image, 0x60, 0xF0, 0x60); $col_black = imagecolorallocate($image, 0, 0, 0); imagecolortransparent($image,$col_white); switch ($MYREQUEST['IMG']) { case 1: $s=$mem['num_seg']*$mem['seg_size']; $a=$mem['avail_mem']; $x=$y=$size/2; $fuzz = 0.000001; // This block of code creates the pie chart. It is a lot more complex than you // would expect because we try to visualize any memory fragmentation as well. $angle_from = 0; $string_placement=array(); for($i=0; $i<$mem['num_seg']; $i++) { $ptr = 0; $free = $mem['block_lists'][$i]; uasort($free, 'block_sort'); foreach($free as $block) { if($block['offset']!=$ptr) { // Used block $angle_to = $angle_from+($block['offset']-$ptr)/$s; if(($angle_to+$fuzz)>1) $angle_to = 1; if( ($angle_to*360) - ($angle_from*360) >= 1) { fill_arc($image,$x,$y,$size,$angle_from*360,$angle_to*360,$col_black,$col_red); if (($angle_to-$angle_from)>0.05) { array_push($string_placement, array($angle_from,$angle_to)); } } $angle_from = $angle_to; } $angle_to = $angle_from+($block['size'])/$s; if(($angle_to+$fuzz)>1) $angle_to = 1; if( ($angle_to*360) - ($angle_from*360) >= 1) { fill_arc($image,$x,$y,$size,$angle_from*360,$angle_to*360,$col_black,$col_green); if (($angle_to-$angle_from)>0.05) { array_push($string_placement, array($angle_from,$angle_to)); } } $angle_from = $angle_to; $ptr = $block['offset']+$block['size']; } if ($ptr < $mem['seg_size']) { // memory at the end $angle_to = $angle_from + ($mem['seg_size'] - $ptr)/$s; if(($angle_to+$fuzz)>1) $angle_to = 1; fill_arc($image,$x,$y,$size,$angle_from*360,$angle_to*360,$col_black,$col_red); if (($angle_to-$angle_from)>0.05) { array_push($string_placement, array($angle_from,$angle_to)); } } } foreach ($string_placement as $angle) { text_arc($image,$x,$y,$size,$angle[0]*360,$angle[1]*360,$col_black,bsize($s*($angle[1]-$angle[0]))); } break; case 2: $s=$cache['num_hits']+$cache['num_misses']; $a=$cache['num_hits']; fill_box($image, 30,$size,50,$s ? (-$a*($size-21)/$s) : 0,$col_black,$col_green,sprintf("%.1f%%",$s ? $cache['num_hits']*100/$s : 0)); fill_box($image,130,$size,50,$s ? -max(4,($s-$a)*($size-21)/$s) : 0,$col_black,$col_red,sprintf("%.1f%%",$s ? $cache['num_misses']*100/$s : 0)); break; case 3: $s=$mem['num_seg']*$mem['seg_size']; $a=$mem['avail_mem']; $x=130; $y=1; $j=1; // This block of code creates the bar chart. It is a lot more complex than you // would expect because we try to visualize any memory fragmentation as well. for($i=0; $i<$mem['num_seg']; $i++) { $ptr = 0; $free = $mem['block_lists'][$i]; uasort($free, 'block_sort'); foreach($free as $block) { if($block['offset']!=$ptr) { // Used block $h=(GRAPH_SIZE-5)*($block['offset']-$ptr)/$s; if ($h>0) { $j++; if($j<75) fill_box($image,$x,$y,50,$h,$col_black,$col_red,bsize($block['offset']-$ptr),$j); else fill_box($image,$x,$y,50,$h,$col_black,$col_red); } $y+=$h; } $h=(GRAPH_SIZE-5)*($block['size'])/$s; if ($h>0) { $j++; if($j<75) fill_box($image,$x,$y,50,$h,$col_black,$col_green,bsize($block['size']),$j); else fill_box($image,$x,$y,50,$h,$col_black,$col_green); } $y+=$h; $ptr = $block['offset']+$block['size']; } if ($ptr < $mem['seg_size']) { // memory at the end $h = (GRAPH_SIZE-5) * ($mem['seg_size'] - $ptr) / $s; if ($h > 0) { fill_box($image,$x,$y,50,$h,$col_black,$col_red,bsize($mem['seg_size']-$ptr),$j++); } } } break; case 4: $s=$cache['num_hits']+$cache['num_misses']; $a=$cache['num_hits']; fill_box($image, 30,$size,50,$s ? -$a*($size-21)/$s : 0,$col_black,$col_green,sprintf("%.1f%%", $s ? $cache['num_hits']*100/$s : 0)); fill_box($image,130,$size,50,$s ? -max(4,($s-$a)*($size-21)/$s) : 0,$col_black,$col_red,sprintf("%.1f%%", $s ? $cache['num_misses']*100/$s : 0)); break; } header("Content-type: image/png"); imagepng($image); exit; } // pretty printer for byte values // function bsize($s) { foreach (array('','K','M','G') as $i => $k) { if ($s < 1024) break; $s/=1024; } return sprintf("%5.1f %sBytes",$s,$k); } // sortable table header in "scripts for this host" view function sortheader($key,$name,$extra='') { global $MYREQUEST, $MY_SELF_WO_SORT; if ($MYREQUEST['SORT1']==$key) { $MYREQUEST['SORT2'] = $MYREQUEST['SORT2']=='A' ? 'D' : 'A'; } return "$name"; } // create menu entry function menu_entry($ob,$title) { global $MYREQUEST,$MY_SELF; if ($MYREQUEST['OB']!=$ob) { return "
  • $title
  • "; } else if (empty($MYREQUEST['SH'])) { return "
  • $title
  • "; } else { return "
  • $title
  • "; } } function put_login_link($s="Login") { global $MY_SELF,$MYREQUEST,$AUTHENTICATED; // needs ADMIN_PASSWORD to be changed! // if (!USE_AUTHENTICATION) { return; } else if (ADMIN_PASSWORD=='password') { print <<$s EOB; } else if ($AUTHENTICATED) { print <<$s EOB; } } function block_sort($array1, $array2) { if ($array1['offset'] > $array2['offset']) { return 1; } else { return -1; } } ?> APCu INFO <?php echo $host ?>

    User Cache


  • Refresh Data
  • EOB; echo menu_entry(OB_HOST_STATS,'View Host Stats'), menu_entry(OB_USER_CACHE,'User Cache Entries'), menu_entry(OB_VERSION_CHECK,'Version Check'); if ($AUTHENTICATED) { echo <<Clear Cache EOB; } echo << EOB; // CONTENT echo << EOB; // MAIN SWITCH STATEMENT switch ($MYREQUEST['OB']) { // ----------------------------------------------- // Host Stats // ----------------------------------------------- case OB_HOST_STATS: $mem_size = $mem['num_seg']*$mem['seg_size']; $mem_avail= $mem['avail_mem']; $mem_used = $mem_size-$mem_avail; $seg_size = bsize($mem['seg_size']); $elapsed = max($time-$cache['start_time'], 1); $req_rate_user = sprintf("%.2f", $cache['num_hits'] ? (($cache['num_hits']+$cache['num_misses'])/$elapsed) : 0); $hit_rate_user = sprintf("%.2f", $cache['num_hits'] ? (($cache['num_hits'])/$elapsed) : 0); $miss_rate_user = sprintf("%.2f", $cache['num_misses'] ? (($cache['num_misses'])/$elapsed) : 0); $insert_rate_user = sprintf("%.2f", $cache['num_inserts'] ? (($cache['num_inserts'])/$elapsed) : 0); $apcversion = phpversion('apcu'); $phpversion = phpversion(); $number_vars = $cache['num_entries']; $size_vars = bsize($cache['mem_size']); $num_hits_and_misses = $cache['num_hits'] + $cache['num_misses']; $num_hits_and_misses = 0 >= $num_hits_and_misses ? 1 : $num_hits_and_misses; $i=0; echo <<< EOB

    General Cache Information

    EOB; if(!empty($_SERVER['SERVER_NAME'])) echo "\n"; if(!empty($_SERVER['SERVER_SOFTWARE'])) echo "\n"; echo << EOB; echo ''; echo ''; echo <<
    APCu Version$apcversion
    PHP Version$phpversion
    APCu Host{$_SERVER['SERVER_NAME']} $host
    Server Software{$_SERVER['SERVER_SOFTWARE']}
    Shared Memory{$mem['num_seg']} Segment(s) with $seg_size
    ({$cache['memory_type']} memory)
    Start Time',date(DATE_FORMAT,$cache['start_time']),'
    Uptime',duration($cache['start_time']),'

    Cache Information

    Cached Variables$number_vars ($size_vars)
    Hits{$cache['num_hits']}
    Misses{$cache['num_misses']}
    Request Rate (hits, misses)$req_rate_user cache requests/second
    Hit Rate$hit_rate_user cache requests/second
    Miss Rate$miss_rate_user cache requests/second
    Insert Rate$insert_rate_user cache requests/second
    Cache full count{$cache['expunges']}

    Runtime Settings

    EOB; $j = 0; foreach (ini_get_all('apcu') as $k => $v) { echo "\n"; $j = 1 - $j; } if($mem['num_seg']>1 || $mem['num_seg']==1 && count($mem['block_lists'][0])>1) $mem_note = "Memory Usage
    (multiple slices indicate fragments)"; else $mem_note = "Memory Usage"; echo <<< EOB
    ",$k,"",str_replace(',',',
    ',$v['local_value'] ?? ''),"

    Host Status Diagrams

    EOB; $size='width='.(GRAPH_SIZE+50).' height='.(GRAPH_SIZE+10); echo << EOB; echo graphics_avail() ? ''. "". "\n" : "", '', '\n", '\n", '', '', '\n", '\n"; echo <<< EOB
    $mem_note Hits & Misses
    \"\"\"\"
     Free: ',bsize($mem_avail).sprintf(" (%.1f%%)",$mem_avail*100/$mem_size)," Hits: ',$cache['num_hits'].@sprintf(" (%.1f%%)",$cache['num_hits']*100/$num_hits_and_misses),"
     Used: ',bsize($mem_used).sprintf(" (%.1f%%)",$mem_used *100/$mem_size)," Misses: ',$cache['num_misses'].@sprintf(" (%.1f%%)",$cache['num_misses']*100/$num_hits_and_misses),"

    Detailed Memory Usage and Fragmentation

    EOB; if(isset($mem['adist'])) { foreach($mem['adist'] as $i=>$v) { $cur = pow(2,$i); $nxt = pow(2,$i+1)-1; if($i==0) $range = "1"; else $range = "$cur - $nxt"; echo "\n"; } } echo <<

    EOB; // Fragementation: (freeseg - 1) / total_seg $nseg = $freeseg = $fragsize = $freetotal = 0; for($i=0; $i<$mem['num_seg']; $i++) { $ptr = 0; foreach($mem['block_lists'][$i] as $block) { if ($block['offset'] != $ptr) { ++$nseg; } $ptr = $block['offset'] + $block['size']; /* Only consider blocks <5M for the fragmentation % */ if($block['size']<(5*1024*1024)) $fragsize+=$block['size']; $freetotal+=$block['size']; } $freeseg += count($mem['block_lists'][$i]); } if ($freeseg > 1) { $frag = sprintf("%.2f%% (%s out of %s in %d fragments)", ($fragsize/$freetotal)*100,bsize($fragsize),bsize($freetotal),$freeseg); } else { $frag = "0%"; } if (graphics_avail()) { $size='width='.(2*GRAPH_SIZE+150).' height='.(GRAPH_SIZE+10); echo << EOB; } echo <<Fragmentation: $frag
    $range$v
    EOB; break; // ----------------------------------------------- // User Cache Entries // ----------------------------------------------- case OB_USER_CACHE: if (!$AUTHENTICATED) { echo '
    You need to login to see the user values here!
     
    '; put_login_link("Login now!"); echo '
    '; break; } $fieldname='info'; $fieldheading='User Entry Label'; $fieldkey='info'; $cols=6; echo <<
    Scope: ", ", Sorting:', '', '', '  Search: ', ' ', '
    '; if (isset($MYREQUEST['SEARCH'])) { // Don't use preg_quote because we want the user to be able to specify a // regular expression subpattern. $MYREQUEST['SEARCH_REGEX'] = '/'.str_replace('/', '\\/', $MYREQUEST['SEARCH']).'/i'; if (preg_match($MYREQUEST['SEARCH_REGEX'], 'test') === false) { echo '
    Error: enter a valid regular expression as a search query.
    '; break; } } echo '
    ', '', '', '', '', '', '', ''; if($fieldname=='info') { $cols+=2; echo ''; } echo ''; // builds list with alpha numeric sortable keys // $list = array(); foreach($cache[$scope_list[$MYREQUEST['SCOPE']]] as $i => $entry) { switch($MYREQUEST['SORT1']) { case 'A': $k=sprintf('%015d-',$entry['access_time']); break; case 'H': $k=sprintf('%015d-',$entry['num_hits']); break; case 'Z': $k=sprintf('%015d-',$entry['mem_size']); break; case 'M': $k=sprintf('%015d-',$entry['mtime']); break; case 'C': $k=sprintf('%015d-',$entry['creation_time']); break; case 'T': $k=sprintf('%015d-',$entry['ttl']); break; case 'D': $k=sprintf('%015d-',$entry['deletion_time']); break; case 'S': $k=$entry["info"]; break; } if (!$AUTHENTICATED) { // hide all path entries if not logged in $list[$k.$entry[$fieldname]]=preg_replace('/^.*(\\/|\\\\)/','*hidden*/',$entry); } else { $list[$k.$entry[$fieldname]]=$entry; } } if ($list) { // sort list // switch ($MYREQUEST['SORT2']) { case "A": krsort($list); break; case "D": ksort($list); break; } // output list $i=0; foreach($list as $k => $entry) { if(empty($MYREQUEST['SEARCH_REGEX']) || preg_match($MYREQUEST['SEARCH_REGEX'], $entry[$fieldname]) != 0) { $sh=md5($entry["info"]); $field_value = htmlentities(strip_tags($entry[$fieldname],''), ENT_QUOTES, 'UTF-8'); if ($sh == $MYREQUEST["SH"]) { $shstr = ""; } else { $shstr = "&SH=" . $sh; } $href = "$MY_SELF&OB=" . $MYREQUEST['OB'] . (!empty($MYREQUEST['SEARCH']) ? "&SEARCH=" . urlencode($MYREQUEST['SEARCH']) : '') . $shstr . "#key-" . $sh; echo '', "', '', '', '', '', ''; if($fieldname=='info') { if($entry['ttl']) { echo ''; } else { echo ''; } } if ($entry['deletion_time']) { echo ''; } else if ($MYREQUEST['OB'] == OB_USER_CACHE) { echo ''; } else { echo ''; } echo ''; if ($sh == $MYREQUEST["SH"]) { echo ''; echo ''; echo ''; } $i++; if ($i == $MYREQUEST['COUNT']) { break; } } } } else { echo ''; } echo <<< EOB
    ',sortheader('S',$fieldheading, "&OB=".$MYREQUEST['OB']),'',sortheader('H','Hits', "&OB=".$MYREQUEST['OB']),'',sortheader('Z','Size', "&OB=".$MYREQUEST['OB']),'',sortheader('A','Last accessed',"&OB=".$MYREQUEST['OB']),'',sortheader('M','Last modified',"&OB=".$MYREQUEST['OB']),'',sortheader('C','Created at', "&OB=".$MYREQUEST['OB']),'',sortheader('T','Timeout',"&OB=".$MYREQUEST['OB']),'',sortheader('D','Deleted at',"&OB=".$MYREQUEST['OB']),'
    ",$field_value,'',$entry['num_hits'],'',$entry['mem_size'],'',date(DATE_FORMAT,$entry['access_time']),'',date(DATE_FORMAT,$entry['mtime']),'',date(DATE_FORMAT,$entry['creation_time']),''.$entry['ttl'].' secondsNone', date(DATE_FORMAT,$entry['deletion_time']), ''; echo '[Delete Now]'; echo '  
    No data
    EOB; if ($list && $i < count($list)) { echo "",count($list)-$i,' more available...'; } echo <<< EOB
    EOB; break; // ----------------------------------------------- // Version check // ----------------------------------------------- case OB_VERSION_CHECK: echo <<

    APCu Version Information

    EOB; if (defined('PROXY')) { $ctxt = stream_context_create( array( 'http' => array( 'proxy' => PROXY, 'request_fulluri' => true ) ) ); $rss = @file_get_contents("https://pecl.php.net/feeds/pkg_apcu.rss", false, $ctxt); } else { $rss = @file_get_contents("https://pecl.php.net/feeds/pkg_apcu.rss"); } if (!$rss) { echo ''; } else { $apcversion = phpversion('apcu'); preg_match('!APCu ([0-9.]+)!', $rss, $match); echo ''; echo ''; } echo <<< EOB
    Unable to fetch version information.
    '; if (version_compare($apcversion, $match[1], '>=')) { echo '
    You are running the latest version of APCu ('.$apcversion.')
    '; $i = 3; } else { echo '
    You are running an older version of APCu ('.$apcversion.'), newer version '.$match[1].' is available at https://pecl.php.net/package/APCu/'.$match[1].'
    '; $i = -1; } echo '

    Change Log:


    '; preg_match_all('!<(title|description)>([^<]+)!', $rss, $match); $changelog = $match[2]; for ($j = 2; $j + 1 < count($changelog); $j += 2) { $v = $changelog[$j]; list(, $ver) = explode(' ', $v, 2); if ($i < 0 && version_compare($apcversion, $ver, '>=')) { break; } else if (!$i--) { break; } $changes = $changelog[$j + 1]; echo "".htmlspecialchars($v, ENT_QUOTES, 'UTF-8')."
    "; echo nl2br(htmlspecialchars($changes, ENT_QUOTES, 'UTF-8'))."
    "; } echo '
    EOB; break; } echo <<< EOB EOB; ?> apcu-5.1.23/apc_php.h0000664000175000017500000000544714523735540013315 0ustar nikicnikic/* +----------------------------------------------------------------------+ | APC | +----------------------------------------------------------------------+ | Copyright (c) 2006-2011 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP 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.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Authors: Daniel Cowgill | | George Schlossnagle | | Rasmus Lerdorf | | Arun C. Murthy | | Gopal Vijayaraghavan | +----------------------------------------------------------------------+ This software was contributed to PHP by Community Connect Inc. in 2002 and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1. Future revisions and derivatives of this source code must acknowledge Community Connect Inc. as the original contributor of this module by leaving this note intact in the source code. All other licensing and usage conditions are those of the PHP Group. */ #ifndef APC_PHP_H #define APC_PHP_H /* * The purpose of this header file is to include all PHP and Zend headers that * are typically needed elsewhere in APC. This makes it easy to insure that * all required headers are available. */ #include "php.h" #include "zend.h" #include "zend_API.h" #include "zend_compile.h" #include "zend_hash.h" #include "zend_extensions.h" #if ZEND_MODULE_API_NO >= 20121204 #define ZEND_ENGINE_2_5 #endif #if ZEND_MODULE_API_NO >= 20100409 #define ZEND_ENGINE_2_4 #endif #if ZEND_MODULE_API_NO > 20060613 #define ZEND_ENGINE_2_3 #endif #if ZEND_MODULE_API_NO > 20050922 #define ZEND_ENGINE_2_2 #endif #if ZEND_MODULE_API_NO > 20050921 #define ZEND_ENGINE_2_1 #endif #ifdef ZEND_ENGINE_2_1 #include "zend_vm.h" #endif #ifndef IS_CONSTANT_TYPE_MASK #define IS_CONSTANT_TYPE_MASK (~IS_CONSTANT_INDEX) #endif #endif /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim>600: noexpandtab sw=4 ts=4 sts=4 fdm=marker * vim<600: noexpandtab sw=4 ts=4 sts=4 */ apcu-5.1.23/apc_shm.c0000664000175000017500000000710414523735540013300 0ustar nikicnikic/* +----------------------------------------------------------------------+ | APC | +----------------------------------------------------------------------+ | Copyright (c) 2006-2011 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP 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.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Authors: Daniel Cowgill | | Rasmus Lerdorf | +----------------------------------------------------------------------+ This software was contributed to PHP by Community Connect Inc. in 2002 and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1. Future revisions and derivatives of this source code must acknowledge Community Connect Inc. as the original contributor of this module by leaving this note intact in the source code. All other licensing and usage conditions are those of the PHP Group. */ #include "apc_shm.h" #include "apc.h" #ifdef PHP_WIN32 /* shm functions are available in TSRM */ #include #define key_t long #else #include #include #include #endif #ifndef SHM_R # define SHM_R 0444 /* read permission */ #endif #ifndef SHM_A # define SHM_A 0222 /* write permission */ #endif int apc_shm_create(int proj, size_t size) { int shmid; /* shared memory id */ int oflag; /* permissions on shm */ key_t key = IPC_PRIVATE; /* shm key */ oflag = IPC_CREAT | SHM_R | SHM_A; if ((shmid = shmget(key, size, oflag)) < 0) { zend_error_noreturn(E_CORE_ERROR, "apc_shm_create: shmget(%d, %zd, %d) failed: %s. It is possible that the chosen SHM segment size is higher than the operation system allows. Linux has usually a default limit of 32MB per segment.", key, size, oflag, strerror(errno)); } return shmid; } void apc_shm_destroy(int shmid) { /* we expect this call to fail often, so we do not check */ shmctl(shmid, IPC_RMID, 0); } apc_segment_t apc_shm_attach(int shmid, size_t size) { apc_segment_t segment; /* shm segment */ if ((zend_long)(segment.shmaddr = shmat(shmid, 0, 0)) == -1) { zend_error_noreturn(E_CORE_ERROR, "apc_shm_attach: shmat failed:"); } #ifdef APC_MEMPROTECT if ((zend_long)(segment.roaddr = shmat(shmid, 0, SHM_RDONLY)) == -1) { segment.roaddr = NULL; } #endif segment.size = size; /* * We set the shmid for removal immediately after attaching to it. The * segment won't disappear until all processes have detached from it. */ apc_shm_destroy(shmid); return segment; } void apc_shm_detach(apc_segment_t* segment) { if (shmdt(segment->shmaddr) < 0) { apc_warning("apc_shm_detach: shmdt failed:"); } #ifdef APC_MEMPROTECT if (segment->roaddr && shmdt(segment->roaddr) < 0) { apc_warning("apc_shm_detach: shmdt failed:"); } #endif } /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim>600: noexpandtab sw=4 ts=4 sts=4 fdm=marker * vim<600: noexpandtab sw=4 ts=4 sts=4 */ apcu-5.1.23/apc_shm.h0000664000175000017500000000405114523735540013303 0ustar nikicnikic/* +----------------------------------------------------------------------+ | APC | +----------------------------------------------------------------------+ | Copyright (c) 2006-2011 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP 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.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Authors: Daniel Cowgill | +----------------------------------------------------------------------+ This software was contributed to PHP by Community Connect Inc. in 2002 and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1. Future revisions and derivatives of this source code must acknowledge Community Connect Inc. as the original contributor of this module by leaving this note intact in the source code. All other licensing and usage conditions are those of the PHP Group. */ #ifndef APC_SHM_H #define APC_SHM_H #include #ifdef PHP_WIN32 #include #endif #include "apc_sma.h" /* Wrapper functions for unix shared memory */ extern int apc_shm_create(int proj, size_t size); extern void apc_shm_destroy(int shmid); extern apc_segment_t apc_shm_attach(int shmid, size_t size); extern void apc_shm_detach(apc_segment_t* segment); #endif /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim>600: noexpandtab sw=4 ts=4 sts=4 fdm=marker * vim<600: noexpandtab sw=4 ts=4 sts=4 */ apcu-5.1.23/apc_signal.c0000664000175000017500000001532414523735540013771 0ustar nikicnikic/* +----------------------------------------------------------------------+ | APC | +----------------------------------------------------------------------+ | Copyright (c) 2006-2011 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP 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.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Authors: Lucas Nealan | +----------------------------------------------------------------------+ This software was contributed to PHP by Facebook Inc. in 2007. Future revisions and derivatives of this source code must acknowledge Facebook Inc. as the original contributor of this module by leaving this note intact in the source code. All other licensing and usage conditions are those of the PHP Group. */ /* Allows apc to install signal handlers and maintain signalling * to already registered handlers. Registers all signals that * coredump by default and unmaps the shared memory segment * before the coredump. Note: PHP module init is called before * signals are set by Apache and thus apc_set_signals should * be called in request init (RINIT) */ #include "apc.h" #if HAVE_SIGACTION #include #include "apc_globals.h" #include "apc_sma.h" #include "apc_signal.h" #include "apc_cache.h" static apc_signal_info_t apc_signal_info = {0}; static int apc_register_signal(int signo, void (*handler)(int, siginfo_t*, void*)); static void apc_rehandle_signal(int signo, siginfo_t *siginfo, void *context); static void apc_core_unmap(int signo, siginfo_t *siginfo, void *context); #if defined(SIGUSR1) && defined(APC_CLEAR_SIGNAL) static void apc_clear_cache(int signo, siginfo_t *siginfo, void *context); #endif extern apc_cache_t* apc_user_cache; /* {{{ apc_core_unmap * Coredump signal handler, detached from shm and calls previously installed handlers */ static void apc_core_unmap(int signo, siginfo_t *siginfo, void *context) { if (apc_user_cache) { apc_sma_detach(apc_user_cache->sma); } apc_rehandle_signal(signo, siginfo, context); #if !defined(WIN32) && !defined(NETWARE) kill(getpid(), signo); #else raise(signo); #endif } /* }}} */ #if defined(SIGUSR1) && defined(APC_CLEAR_SIGNAL) /* {{{ apc_reload_cache */ static void apc_clear_cache(int signo, siginfo_t *siginfo, void *context) { if (apc_user_cache) { apc_cache_clear(apc_user_cache); } apc_rehandle_signal(signo, siginfo, context); #if !defined(WIN32) && !defined(NETWARE) kill(getpid(), signo); #else raise(signo); #endif } /* }}} */ #endif /* {{{ apc_rehandle_signal * Call the previously registered handler for a signal */ static void apc_rehandle_signal(int signo, siginfo_t *siginfo, void *context) { int i; apc_signal_entry_t p_sig = {0}; for (i=0; (i < apc_signal_info.installed && p_sig.signo != signo); i++) { p_sig = *apc_signal_info.prev[i]; if (p_sig.signo == signo) { if (p_sig.siginfo) { (*(void (*)(int, siginfo_t*, void*))p_sig.handler)(signo, siginfo, context); } else { (*(void (*)(int))p_sig.handler)(signo); } } } } /* }}} */ /* {{{ apc_register_signal * Set a handler for a previously installed signal and save so we can * callback when handled */ static int apc_register_signal(int signo, void (*handler)(int, siginfo_t*, void*)) { struct sigaction sa; apc_signal_entry_t p_sig = {0}; if (sigaction(signo, NULL, &sa) == 0) { if ((void*)sa.sa_handler == (void*)handler) { return SUCCESS; } if (sa.sa_handler != SIG_ERR && sa.sa_handler != SIG_DFL && sa.sa_handler != SIG_IGN) { p_sig.signo = signo; p_sig.siginfo = ((sa.sa_flags & SA_SIGINFO) == SA_SIGINFO); p_sig.handler = (void *)sa.sa_handler; apc_signal_info.prev = (apc_signal_entry_t **) perealloc(apc_signal_info.prev, (apc_signal_info.installed+1)*sizeof(apc_signal_entry_t *), 1); apc_signal_info.prev[apc_signal_info.installed] = (apc_signal_entry_t *) pemalloc(sizeof(apc_signal_entry_t), 1); *apc_signal_info.prev[apc_signal_info.installed++] = p_sig; } else { /* inherit flags and mask if already set */ sigemptyset(&sa.sa_mask); sa.sa_flags = 0; sa.sa_flags |= SA_SIGINFO; /* we'll use a siginfo handler */ #if defined(SA_ONESHOT) sa.sa_flags = SA_ONESHOT; #elif defined(SA_RESETHAND) sa.sa_flags = SA_RESETHAND; #endif } sa.sa_handler = (void*)handler; if (sigaction(signo, &sa, NULL) < 0) { apc_warning("Error installing apc signal handler for %d", signo); } return SUCCESS; } return FAILURE; } /* }}} */ /* {{{ apc_set_signals * Install our signal handlers */ void apc_set_signals() { if (apc_signal_info.installed == 0) { #if defined(SIGUSR1) && defined(APC_CLEAR_SIGNAL) apc_register_signal(SIGUSR1, apc_clear_cache); #endif if (APCG(coredump_unmap)) { /* ISO C standard signals that coredump */ apc_register_signal(SIGSEGV, apc_core_unmap); apc_register_signal(SIGABRT, apc_core_unmap); apc_register_signal(SIGFPE, apc_core_unmap); apc_register_signal(SIGILL, apc_core_unmap); /* extended signals that coredump */ #ifdef SIGBUS apc_register_signal(SIGBUS, apc_core_unmap); #endif #ifdef SIGABORT apc_register_signal(SIGABORT, apc_core_unmap); #endif #ifdef SIGEMT apc_register_signal(SIGEMT, apc_core_unmap); #endif #ifdef SIGIOT apc_register_signal(SIGIOT, apc_core_unmap); #endif #ifdef SIGQUIT apc_register_signal(SIGQUIT, apc_core_unmap); #endif #ifdef SIGSYS apc_register_signal(SIGSYS, apc_core_unmap); #endif #ifdef SIGTRAP apc_register_signal(SIGTRAP, apc_core_unmap); #endif #ifdef SIGXCPU apc_register_signal(SIGXCPU, apc_core_unmap); #endif #ifdef SIGXFSZ apc_register_signal(SIGXFSZ, apc_core_unmap); #endif } } } /* }}} */ /* {{{ apc_set_signals * cleanup signals for shutdown */ void apc_shutdown_signals() { int i=0; if (apc_signal_info.installed > 0) { for (i=0; i < apc_signal_info.installed; i++) { free(apc_signal_info.prev[i]); } free(apc_signal_info.prev); apc_signal_info.installed = 0; /* just in case */ } } /* }}} */ #endif /* HAVE_SIGACTION */ /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim>600: noexpandtab sw=4 ts=4 sts=4 fdm=marker * vim<600: noexpandtab sw=4 ts=4 sts=4 */ apcu-5.1.23/apc_signal.h0000664000175000017500000000347514523735540014002 0ustar nikicnikic/* +----------------------------------------------------------------------+ | APC | +----------------------------------------------------------------------+ | Copyright (c) 2006-2011 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP 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.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Authors: Lucas Nealan | +----------------------------------------------------------------------+ */ #ifndef APC_SIGNAL_H #define APC_SIGNAL_H #include "apc.h" #include "apc_php.h" typedef struct apc_signal_entry_t { int signo; /* signal number */ int siginfo; /* siginfo style handler calling */ void* handler; /* signal handler */ } apc_signal_entry_t; typedef struct apc_signal_info_t { int installed; /* How many signals we've installed handles for */ apc_signal_entry_t **prev; /* Previous signal handlers */ } apc_signal_info_t; void apc_set_signals(void); void apc_shutdown_signals(void); #endif /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim>600: noexpandtab sw=4 ts=4 sts=4 fdm=marker * vim<600: noexpandtab sw=4 ts=4 sts=4 */ apcu-5.1.23/apc_sma.c0000664000175000017500000004074014523735540013274 0ustar nikicnikic/* +----------------------------------------------------------------------+ | APC | +----------------------------------------------------------------------+ | Copyright (c) 2006-2011 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP 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.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Authors: Daniel Cowgill | | Rasmus Lerdorf | +----------------------------------------------------------------------+ This software was contributed to PHP by Community Connect Inc. in 2002 and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1. Future revisions and derivatives of this source code must acknowledge Community Connect Inc. as the original contributor of this module by leaving this note intact in the source code. All other licensing and usage conditions are those of the PHP Group. */ #include "apc_sma.h" #include "apc.h" #include "apc_globals.h" #include "apc_mutex.h" #include "apc_shm.h" #include "apc_cache.h" #include #include "apc_mmap.h" #ifdef APC_SMA_DEBUG # ifdef HAVE_VALGRIND_MEMCHECK_H # include # endif # define APC_SMA_CANARIES 1 #endif enum { DEFAULT_NUMSEG=1, DEFAULT_SEGSIZE=30*1024*1024 }; typedef struct sma_header_t sma_header_t; struct sma_header_t { apc_mutex_t sma_lock; /* segment lock */ size_t segsize; /* size of entire segment */ size_t avail; /* bytes available (not necessarily contiguous) */ }; #define SMA_HDR(sma, i) ((sma_header_t*)((sma->segs[i]).shmaddr)) #define SMA_ADDR(sma, i) ((char*)(SMA_HDR(sma, i))) #define SMA_RO(sma, i) ((char*)(sma->segs[i]).roaddr) #define SMA_LCK(sma, i) ((SMA_HDR(sma, i))->sma_lock) #define SMA_CREATE_LOCK APC_CREATE_MUTEX #define SMA_DESTROY_LOCK APC_DESTROY_MUTEX #define SMA_LOCK(sma, i) APC_MUTEX_LOCK(&SMA_LCK(sma, i)) #define SMA_UNLOCK(sma, i) APC_MUTEX_UNLOCK(&SMA_LCK(sma, i)) #if 0 /* global counter for identifying blocks * Technically it is possible to do the same * using offsets, but double allocations of the * same offset can happen. */ static volatile size_t block_id = 0; #endif typedef struct block_t block_t; struct block_t { size_t size; /* size of this block */ size_t prev_size; /* size of sequentially previous block, 0 if prev is allocated */ size_t fnext; /* offset in segment of next free block */ size_t fprev; /* offset in segment of prev free block */ #ifdef APC_SMA_CANARIES size_t canary; /* canary to check for memory overwrites */ #endif #if 0 size_t id; /* identifier for the memory block */ #endif }; /* The macros BLOCKAT and OFFSET are used for convenience throughout this * module. Both assume the presence of a variable shmaddr that points to the * beginning of the shared memory segment in question. */ #define BLOCKAT(offset) ((block_t*)((char *)shmaddr + offset)) #define OFFSET(block) ((size_t)(((char*)block) - (char*)shmaddr)) /* macros for getting the next or previous sequential block */ #define NEXT_SBLOCK(block) ((block_t*)((char*)block + block->size)) #define PREV_SBLOCK(block) (block->prev_size ? ((block_t*)((char*)block - block->prev_size)) : NULL) /* Canary macros for setting, checking and resetting memory canaries */ #ifdef APC_SMA_CANARIES #define SET_CANARY(v) (v)->canary = 0x42424242 #define CHECK_CANARY(v) assert((v)->canary == 0x42424242) #define RESET_CANARY(v) (v)->canary = -42 #else #define SET_CANARY(v) #define CHECK_CANARY(v) #define RESET_CANARY(v) #endif #define MINBLOCKSIZE (ALIGNWORD(1) + ALIGNWORD(sizeof(block_t))) /* How many extra blocks to check for a better fit */ #define BEST_FIT_LIMIT 3 static inline block_t *find_block(sma_header_t *header, size_t realsize) { void *shmaddr = header; block_t *cur, *prv = BLOCKAT(ALIGNWORD(sizeof(sma_header_t))); block_t *found = NULL; uint32_t i; CHECK_CANARY(prv); while (prv->fnext) { cur = BLOCKAT(prv->fnext); CHECK_CANARY(cur); /* Found a suitable block */ if (cur->size >= realsize) { found = cur; break; } prv = cur; } if (found) { /* Try to find a smaller block that also fits */ prv = cur; for (i = 0; i < BEST_FIT_LIMIT && prv->fnext; i++) { cur = BLOCKAT(prv->fnext); CHECK_CANARY(cur); if (cur->size >= realsize && cur->size < found->size) { found = cur; } prv = cur; } } return found; } /* {{{ sma_allocate: tries to allocate at least size bytes in a segment */ static APC_HOTSPOT size_t sma_allocate(sma_header_t *header, size_t size, size_t fragment, size_t *allocated) { void* shmaddr; /* header of shared memory segment */ block_t* prv; /* block prior to working block */ block_t* cur; /* working block in list */ size_t realsize; /* actual size of block needed, including header */ size_t block_size = ALIGNWORD(sizeof(struct block_t)); realsize = ALIGNWORD(size + block_size); /* * First, insure that the segment contains at least realsize free bytes, * even if they are not contiguous. */ shmaddr = header; if (header->avail < realsize) { return SIZE_MAX; } cur = find_block(header, realsize); if (!cur) { /* No suitable block found */ return SIZE_MAX; } if (cur->size == realsize || (cur->size > realsize && cur->size < (realsize + (MINBLOCKSIZE + fragment)))) { /* cur is big enough for realsize, but too small to split - unlink it */ *(allocated) = cur->size - block_size; prv = BLOCKAT(cur->fprev); prv->fnext = cur->fnext; BLOCKAT(cur->fnext)->fprev = OFFSET(prv); NEXT_SBLOCK(cur)->prev_size = 0; /* block is alloc'd */ } else { /* nextfit is too big; split it into two smaller blocks */ block_t* nxt; /* the new block (chopped part of cur) */ size_t oldsize; /* size of cur before split */ oldsize = cur->size; cur->size = realsize; *(allocated) = cur->size - block_size; nxt = NEXT_SBLOCK(cur); nxt->prev_size = 0; /* block is alloc'd */ nxt->size = oldsize - realsize; /* and fix the size */ NEXT_SBLOCK(nxt)->prev_size = nxt->size; /* adjust size */ SET_CANARY(nxt); /* replace cur with next in free list */ nxt->fnext = cur->fnext; nxt->fprev = cur->fprev; BLOCKAT(nxt->fnext)->fprev = OFFSET(nxt); BLOCKAT(nxt->fprev)->fnext = OFFSET(nxt); #if 0 nxt->id = -1; #endif } cur->fnext = 0; /* update the block header */ header->avail -= cur->size; SET_CANARY(cur); #if 0 cur->id = ++block_id; fprintf(stderr, "allocate(realsize=%d,size=%d,id=%d)\n", (int)(size), (int)(cur->size), cur->id); #endif return OFFSET(cur) + block_size; } /* }}} */ /* {{{ sma_deallocate: deallocates the block at the given offset */ static APC_HOTSPOT size_t sma_deallocate(void* shmaddr, size_t offset) { sma_header_t* header; /* header of shared memory segment */ block_t* cur; /* the new block to insert */ block_t* prv; /* the block before cur */ block_t* nxt; /* the block after cur */ size_t size; /* size of deallocated block */ assert(offset >= ALIGNWORD(sizeof(struct block_t))); offset -= ALIGNWORD(sizeof(struct block_t)); /* find position of new block in free list */ cur = BLOCKAT(offset); /* update the block header */ header = (sma_header_t*) shmaddr; header->avail += cur->size; size = cur->size; if (cur->prev_size != 0) { /* remove prv from list */ prv = PREV_SBLOCK(cur); BLOCKAT(prv->fnext)->fprev = prv->fprev; BLOCKAT(prv->fprev)->fnext = prv->fnext; /* cur and prv share an edge, combine them */ prv->size +=cur->size; RESET_CANARY(cur); cur = prv; } nxt = NEXT_SBLOCK(cur); if (nxt->fnext != 0) { assert(NEXT_SBLOCK(NEXT_SBLOCK(cur))->prev_size == nxt->size); /* cur and nxt shared an edge, combine them */ BLOCKAT(nxt->fnext)->fprev = nxt->fprev; BLOCKAT(nxt->fprev)->fnext = nxt->fnext; cur->size += nxt->size; CHECK_CANARY(nxt); #if 0 nxt->id = -1; /* assert this or set it ? */ #endif RESET_CANARY(nxt); } NEXT_SBLOCK(cur)->prev_size = cur->size; /* insert new block after prv */ prv = BLOCKAT(ALIGNWORD(sizeof(sma_header_t))); cur->fnext = prv->fnext; prv->fnext = OFFSET(cur); cur->fprev = OFFSET(prv); BLOCKAT(cur->fnext)->fprev = OFFSET(cur); return size; } /* }}} */ /* {{{ APC SMA API */ PHP_APCU_API void apc_sma_init(apc_sma_t* sma, void** data, apc_sma_expunge_f expunge, int32_t num, size_t size, char *mask) { int32_t i; if (sma->initialized) { return; } sma->initialized = 1; sma->expunge = expunge; sma->data = data; #if APC_MMAP /* * I don't think multiple anonymous mmaps makes any sense * so force sma_numseg to 1 in this case */ if(!mask || (mask && !strlen(mask)) || (mask && !strcmp(mask, "/dev/zero"))) { sma->num = 1; } else { sma->num = num > 0 ? num : DEFAULT_NUMSEG; } #else sma->num = num > 0 ? num : DEFAULT_NUMSEG; #endif sma->size = size > 0 ? size : DEFAULT_SEGSIZE; sma->segs = (apc_segment_t*) pemalloc(sma->num * sizeof(apc_segment_t), 1); for (i = 0; i < sma->num; i++) { sma_header_t* header; block_t *first, *empty, *last; void* shmaddr; #if APC_MMAP sma->segs[i] = apc_mmap(mask, sma->size); if(sma->num != 1) memcpy(&mask[strlen(mask)-6], "XXXXXX", 6); #else { int j = apc_shm_create(i, sma->size); #if PHP_WIN32 /* TODO remove the line below after 7.1 EOL. */ SetLastError(0); #endif sma->segs[i] = apc_shm_attach(j, sma->size); } #endif sma->segs[i].size = sma->size; shmaddr = sma->segs[i].shmaddr; header = (sma_header_t*) shmaddr; SMA_CREATE_LOCK(&header->sma_lock); header->segsize = sma->size; header->avail = sma->size - ALIGNWORD(sizeof(sma_header_t)) - ALIGNWORD(sizeof(block_t)) - ALIGNWORD(sizeof(block_t)); first = BLOCKAT(ALIGNWORD(sizeof(sma_header_t))); first->size = 0; first->fnext = ALIGNWORD(sizeof(sma_header_t)) + ALIGNWORD(sizeof(block_t)); first->fprev = 0; first->prev_size = 0; SET_CANARY(first); #if 0 first->id = -1; #endif empty = BLOCKAT(first->fnext); empty->size = header->avail - ALIGNWORD(sizeof(block_t)); empty->fnext = OFFSET(empty) + empty->size; empty->fprev = ALIGNWORD(sizeof(sma_header_t)); empty->prev_size = 0; SET_CANARY(empty); #if 0 empty->id = -1; #endif last = BLOCKAT(empty->fnext); last->size = 0; last->fnext = 0; last->fprev = OFFSET(empty); last->prev_size = empty->size; SET_CANARY(last); #if 0 last->id = -1; #endif } } PHP_APCU_API void apc_sma_detach(apc_sma_t* sma) { /* Important: This function should not clean up anything that's in shared memory, * only detach our process-local use of it. In particular locks cannot be destroyed * here. */ int32_t i; assert(sma->initialized); sma->initialized = 0; for (i = 0; i < sma->num; i++) { #if APC_MMAP apc_unmap(&sma->segs[i]); #else apc_shm_detach(&sma->segs[i]); #endif } free(sma->segs); } PHP_APCU_API void *apc_sma_malloc_ex(apc_sma_t *sma, size_t n, size_t *allocated) { size_t fragment = MINBLOCKSIZE; size_t off; int32_t i; zend_bool nuked = 0; int32_t last = sma->last; restart: assert(sma->initialized); if (!SMA_LOCK(sma, last)) { return NULL; } off = sma_allocate(SMA_HDR(sma, last), n, fragment, allocated); if (off != SIZE_MAX) { void* p = (void *)(SMA_ADDR(sma, last) + off); SMA_UNLOCK(sma, last); #ifdef VALGRIND_MALLOCLIKE_BLOCK VALGRIND_MALLOCLIKE_BLOCK(p, n, 0, 0); #endif return p; } SMA_UNLOCK(sma, last); for (i = 0; i < sma->num; i++) { if (i == last) { continue; } if (!SMA_LOCK(sma, i)) { return NULL; } off = sma_allocate(SMA_HDR(sma, i), n, fragment, allocated); if (off != SIZE_MAX) { void* p = (void *)(SMA_ADDR(sma, i) + off); sma->last = i; SMA_UNLOCK(sma, i); #ifdef VALGRIND_MALLOCLIKE_BLOCK VALGRIND_MALLOCLIKE_BLOCK(p, n, 0, 0); #endif return p; } SMA_UNLOCK(sma, i); } /* Expunge cache in hope of freeing up memory, but only once */ if (!nuked) { sma->expunge(*sma->data, n+fragment); nuked = 1; goto restart; } return NULL; } PHP_APCU_API void* apc_sma_malloc(apc_sma_t* sma, size_t n) { size_t allocated; return apc_sma_malloc_ex(sma, n, &allocated); } PHP_APCU_API void apc_sma_free(apc_sma_t* sma, void* p) { int32_t i; size_t offset; if (p == NULL) { return; } assert(sma->initialized); for (i = 0; i < sma->num; i++) { offset = (size_t)((char *)p - SMA_ADDR(sma, i)); if (p >= (void*)SMA_ADDR(sma, i) && offset < sma->size) { if (!SMA_LOCK(sma, i)) { return; } sma_deallocate(SMA_HDR(sma, i), offset); SMA_UNLOCK(sma, i); #ifdef VALGRIND_FREELIKE_BLOCK VALGRIND_FREELIKE_BLOCK(p, 0); #endif return; } } apc_error("apc_sma_free: could not locate address %p", p); } #ifdef APC_MEMPROTECT PHP_APCU_API void* apc_sma_protect(apc_sma_t* sma, void* p) { unsigned int i = 0; size_t offset; if (p == NULL) { return NULL; } if(SMA_RO(sma, sma->last) == NULL) return p; offset = (size_t)((char *)p - SMA_ADDR(sma, sma->last)); if(p >= (void*)SMA_ADDR(sma, sma->last) && offset < sma->size) { return SMA_RO(sma, sma->last) + offset; } for (i = 0; i < sma->num; i++) { offset = (size_t)((char *)p - SMA_ADDR(sma, i)); if (p >= (void*)SMA_ADDR(sma, i) && offset < sma->size) { return SMA_RO(sma, i) + offset; } } return NULL; } PHP_APCU_API void* apc_sma_unprotect(apc_sma_t* sma, void* p){ unsigned int i = 0; size_t offset; if (p == NULL) { return NULL; } if(SMA_RO(sma, sma->last) == NULL) return p; offset = (size_t)((char *)p - SMA_RO(sma, sma->last)); if(p >= (void*)SMA_RO(sma, sma->last) && offset < sma->size) { return SMA_ADDR(sma, sma->last) + offset; } for (i = 0; i < sma->num; i++) { offset = (size_t)((char *)p - SMA_RO(sma, i)); if (p >= (void*)SMA_RO(sma, i) && offset < sma->size) { return SMA_ADDR(sma, i) + offset; } } return NULL; } #else PHP_APCU_API void* apc_sma_protect(apc_sma_t* sma, void *p) { return p; } PHP_APCU_API void* apc_sma_unprotect(apc_sma_t* sma, void *p) { return p; } #endif PHP_APCU_API apc_sma_info_t *apc_sma_info(apc_sma_t* sma, zend_bool limited) { apc_sma_info_t *info; apc_sma_link_t **link; int32_t i; char *shmaddr; block_t *prv; if (!sma->initialized) { return NULL; } info = emalloc(sizeof(apc_sma_info_t)); info->num_seg = sma->num; info->seg_size = sma->size - (ALIGNWORD(sizeof(sma_header_t)) + ALIGNWORD(sizeof(block_t)) + ALIGNWORD(sizeof(block_t))); info->list = emalloc(info->num_seg * sizeof(apc_sma_link_t *)); for (i = 0; i < sma->num; i++) { info->list[i] = NULL; } if (limited) { return info; } /* For each segment */ for (i = 0; i < sma->num; i++) { SMA_LOCK(sma, i); shmaddr = SMA_ADDR(sma, i); prv = BLOCKAT(ALIGNWORD(sizeof(sma_header_t))); link = &info->list[i]; /* For each block in this segment */ while (BLOCKAT(prv->fnext)->fnext != 0) { block_t *cur = BLOCKAT(prv->fnext); CHECK_CANARY(cur); *link = emalloc(sizeof(apc_sma_link_t)); (*link)->size = cur->size; (*link)->offset = prv->fnext; (*link)->next = NULL; link = &(*link)->next; prv = cur; } SMA_UNLOCK(sma, i); } return info; } PHP_APCU_API void apc_sma_free_info(apc_sma_t *sma, apc_sma_info_t *info) { int i; for (i = 0; i < info->num_seg; i++) { apc_sma_link_t *p = info->list[i]; while (p) { apc_sma_link_t *q = p; p = p->next; efree(q); } } efree(info->list); efree(info); } PHP_APCU_API size_t apc_sma_get_avail_mem(apc_sma_t* sma) { size_t avail_mem = 0; int32_t i; for (i = 0; i < sma->num; i++) { sma_header_t* header = SMA_HDR(sma, i); avail_mem += header->avail; } return avail_mem; } PHP_APCU_API zend_bool apc_sma_get_avail_size(apc_sma_t* sma, size_t size) { int32_t i; for (i = 0; i < sma->num; i++) { sma_header_t* header = SMA_HDR(sma, i); if (header->avail > size) { return 1; } } return 0; } PHP_APCU_API void apc_sma_check_integrity(apc_sma_t* sma) { /* dummy */ } /* }}} */ /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim>600: noexpandtab sw=4 ts=4 sts=4 fdm=marker * vim<600: noexpandtab sw=4 ts=4 sts=4 */ apcu-5.1.23/apc_sma.h0000664000175000017500000001275314523735540013304 0ustar nikicnikic/* +----------------------------------------------------------------------+ | APC | +----------------------------------------------------------------------+ | Copyright (c) 2006-2011 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP 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.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Authors: Daniel Cowgill | +----------------------------------------------------------------------+ This software was contributed to PHP by Community Connect Inc. in 2002 and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1. Future revisions and derivatives of this source code must acknowledge Community Connect Inc. as the original contributor of this module by leaving this note intact in the source code. All other licensing and usage conditions are those of the PHP Group. */ #ifndef APC_SMA_H #define APC_SMA_H /* {{{ SMA API APC SMA API provides support for shared memory allocators to external libraries ( and to APC ) Skip to the bottom macros for error free usage of the SMA API */ #include "apc.h" /* {{{ struct definition: apc_segment_t */ typedef struct _apc_segment_t { size_t size; /* size of this segment */ void* shmaddr; /* address of shared memory */ #ifdef APC_MEMPROTECT void* roaddr; /* read only (mprotect'd) address */ #endif } apc_segment_t; /* }}} */ /* {{{ struct definition: apc_sma_link_t */ typedef struct apc_sma_link_t apc_sma_link_t; struct apc_sma_link_t { zend_long size; /* size of this free block */ zend_long offset; /* offset in segment of this block */ apc_sma_link_t* next; /* link to next free block */ }; /* }}} */ /* {{{ struct definition: apc_sma_info_t */ typedef struct apc_sma_info_t apc_sma_info_t; struct apc_sma_info_t { int num_seg; /* number of segments */ size_t seg_size; /* segment size */ apc_sma_link_t** list; /* one list per segment of links */ }; /* }}} */ typedef void (*apc_sma_expunge_f)(void *pointer, size_t size); /* }}} */ /* {{{ struct definition: apc_sma_t */ typedef struct _apc_sma_t { zend_bool initialized; /* flag to indicate this sma has been initialized */ /* callback */ apc_sma_expunge_f expunge; /* expunge */ void** data; /* expunge data */ /* info */ int32_t num; /* number of segments */ size_t size; /* segment size */ int32_t last; /* last segment */ /* segments */ apc_segment_t *segs; /* segments */ } apc_sma_t; /* }}} */ /* * apc_sma_api_init will initialize a shared memory allocator with num segments of the given size * * should be called once per allocator per process */ PHP_APCU_API void apc_sma_init( apc_sma_t* sma, void** data, apc_sma_expunge_f expunge, int32_t num, size_t size, char *mask); /* * apc_sma_detach will detach from shared memory and cleanup local allocations. */ PHP_APCU_API void apc_sma_detach(apc_sma_t* sma); /* * apc_smap_api_malloc will allocate a block from the sma of the given size */ PHP_APCU_API void* apc_sma_malloc(apc_sma_t* sma, size_t size); /* * apc_sma_api_malloc_ex will allocate a block from the sma of the given size and * provide the size of the actual allocation. */ PHP_APCU_API void *apc_sma_malloc_ex( apc_sma_t *sma, size_t size, size_t *allocated); /* * apc_sma_api_free will free p (which should be a pointer to a block allocated from sma) */ PHP_APCU_API void apc_sma_free(apc_sma_t* sma, void* p); /* * apc_sma_api_protect will protect p (which should be a pointer to a block allocated from sma) */ PHP_APCU_API void* apc_sma_protect(apc_sma_t* sma, void* p); /* * apc_sma_api_protect will uprotect p (which should be a pointer to a block allocated from sma) */ PHP_APCU_API void* apc_sma_unprotect(apc_sma_t* sma, void *p); /* * apc_sma_api_info returns information about the allocator */ PHP_APCU_API apc_sma_info_t* apc_sma_info(apc_sma_t* sma, zend_bool limited); /* * apc_sma_api_info_free_info is for freeing apc_sma_info_t* returned by apc_sma_api_info */ PHP_APCU_API void apc_sma_free_info(apc_sma_t* sma, apc_sma_info_t* info); /* * apc_sma_api_get_avail_mem will return the amount of memory available left to sma */ PHP_APCU_API size_t apc_sma_get_avail_mem(apc_sma_t* sma); /* * apc_sma_api_get_avail_size will return true if at least size bytes are available to the sma */ PHP_APCU_API zend_bool apc_sma_get_avail_size(apc_sma_t* sma, size_t size); /* * apc_sma_api_check_integrity will check the integrity of sma */ PHP_APCU_API void apc_sma_check_integrity(apc_sma_t* sma); /* }}} */ /* {{{ ALIGNWORD: pad up x, aligned to the system's word boundary */ typedef union { void* p; int i; long l; double d; void (*f)(void); } apc_word_t; #define ALIGNSIZE(x, size) ((size) * (1 + (((x)-1)/(size)))) #define ALIGNWORD(x) ALIGNSIZE(x, sizeof(apc_word_t)) /* }}} */ #endif apcu-5.1.23/apc_stack.c0000664000175000017500000000564414523735540013625 0ustar nikicnikic/* +----------------------------------------------------------------------+ | APC | +----------------------------------------------------------------------+ | Copyright (c) 2006-2011 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP 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.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Authors: Daniel Cowgill | +----------------------------------------------------------------------+ This software was contributed to PHP by Community Connect Inc. in 2002 and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1. Future revisions and derivatives of this source code must acknowledge Community Connect Inc. as the original contributor of this module by leaving this note intact in the source code. All other licensing and usage conditions are those of the PHP Group. */ #include "apc.h" #include "apc_stack.h" struct apc_stack_t { void** data; size_t capacity; size_t size; }; apc_stack_t* apc_stack_create(size_t size_hint) { apc_stack_t* stack = emalloc(sizeof(apc_stack_t)); stack->capacity = (size_hint > 0) ? size_hint : 10; stack->size = 0; stack->data = emalloc(sizeof(void*) * stack->capacity); return stack; } void apc_stack_destroy(apc_stack_t* stack) { if (stack != NULL) { efree(stack->data); efree(stack); } } void apc_stack_clear(apc_stack_t* stack) { assert(stack != NULL); stack->size = 0; } void apc_stack_push(apc_stack_t* stack, void* item) { assert(stack != NULL); if (stack->size == stack->capacity) { stack->capacity *= 2; stack->data = erealloc(stack->data, sizeof(void*) * stack->capacity); } stack->data[stack->size++] = item; } void* apc_stack_pop(apc_stack_t* stack) { assert(stack != NULL && stack->size > 0); return stack->data[--stack->size]; } void* apc_stack_top(apc_stack_t* stack) { assert(stack != NULL && stack->size > 0); return stack->data[stack->size-1]; } void* apc_stack_get(apc_stack_t* stack, size_t n) { assert(stack != NULL && stack->size > n); return stack->data[n]; } int apc_stack_size(apc_stack_t* stack) { assert(stack != NULL); return stack->size; } /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim>600: noexpandtab sw=4 ts=4 sts=4 fdm=marker * vim<600: noexpandtab sw=4 ts=4 sts=4 */ apcu-5.1.23/apc_stack.h0000664000175000017500000000435314523735540013626 0ustar nikicnikic/* +----------------------------------------------------------------------+ | APC | +----------------------------------------------------------------------+ | Copyright (c) 2006-2011 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP 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.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Authors: Daniel Cowgill | | George Schlossnagle | +----------------------------------------------------------------------+ This software was contributed to PHP by Community Connect Inc. in 2002 and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1. Future revisions and derivatives of this source code must acknowledge Community Connect Inc. as the original contributor of this module by leaving this note intact in the source code. All other licensing and usage conditions are those of the PHP Group. */ #ifndef APC_STACK_H #define APC_STACK_H /* Basic stack datatype */ #define T apc_stack_t* typedef struct apc_stack_t apc_stack_t; /* opaque stack type */ extern T apc_stack_create(size_t size_hint); extern void apc_stack_destroy(T stack); extern void apc_stack_clear(T stack); extern void apc_stack_push(T stack, void* item); extern void* apc_stack_pop(T stack); extern void* apc_stack_top(T stack); extern void* apc_stack_get(T stack, size_t n); extern int apc_stack_size(T stack); #undef T #endif /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim>600: noexpandtab sw=4 ts=4 sts=4 fdm=marker * vim<600: noexpandtab sw=4 ts=4 sts=4 */ apcu-5.1.23/apc_strings.h0000664000175000017500000000271614523735540014213 0ustar nikicnikic/* +----------------------------------------------------------------------+ | APC | +----------------------------------------------------------------------+ | Copyright (c) 2006-2018 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP 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.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Authors: Nikita Popov | +----------------------------------------------------------------------+ */ #ifndef APC_STRINGS_H #define APC_STRINGS_H #define APC_STRINGS \ X(access_time) \ X(creation_time) \ X(deletion_time) \ X(hits) \ X(info) \ X(key) \ X(mem_size) \ X(mtime) \ X(num_hits) \ X(ref_count) \ X(refs) \ X(ttl) \ X(type) \ X(user) \ X(value) \ #define X(str) extern zend_string *apc_str_ ## str; APC_STRINGS #undef X #endif apcu-5.1.23/apc_time.c0000664000175000017500000000343714523735540013454 0ustar nikicnikic/* +----------------------------------------------------------------------+ | APC | +----------------------------------------------------------------------+ | Copyright (c) 2006-2011 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP 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.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ This software was contributed to PHP by Community Connect Inc. in 2002 and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1. Future revisions and derivatives of this source code must acknowledge Community Connect Inc. as the original contributor of this module by leaving this note intact in the source code. All other licensing and usage conditions are those of the PHP Group. */ #include "apc_time.h" #include "apc_globals.h" #include "SAPI.h" time_t apc_time(void) { if (APCG(use_request_time)) { if (!APCG(request_time)) APCG(request_time) = (time_t) sapi_get_request_time(); return APCG(request_time); } else { return time(0); } } /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim>600: noexpandtab sw=4 ts=4 sts=4 fdm=marker * vim<600: noexpandtab sw=4 ts=4 sts=4 */ apcu-5.1.23/apc_time.h0000664000175000017500000000315414523735540013455 0ustar nikicnikic/* +----------------------------------------------------------------------+ | APC | +----------------------------------------------------------------------+ | Copyright (c) 2006-2011 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP 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.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ This software was contributed to PHP by Community Connect Inc. in 2002 and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1. Future revisions and derivatives of this source code must acknowledge Community Connect Inc. as the original contributor of this module by leaving this note intact in the source code. All other licensing and usage conditions are those of the PHP Group. */ #ifndef APC_TIME_H #define APC_TIME_H #include time_t apc_time(void); #endif /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim>600: noexpandtab sw=4 ts=4 sts=4 fdm=marker * vim<600: noexpandtab sw=4 ts=4 sts=4 */ apcu-5.1.23/apc_windows_srwlock_kernel.c0000664000175000017500000000367014523735540017313 0ustar nikicnikic/* +----------------------------------------------------------------------+ | APC | +----------------------------------------------------------------------+ | Copyright (c) 2006-2011 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP 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.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Authors: Pierre Joye | +----------------------------------------------------------------------+ */ #include #ifdef APC_SRWLOCK_KERNEL #include "apc_windows_srwlock_kernel.h" apc_windows_cs_rwlock_t *apc_windows_cs_create(apc_windows_cs_rwlock_t *lock) { InitializeSRWLock(lock); return lock; } void apc_windows_cs_destroy(apc_windows_cs_rwlock_t *lock) { /* pass */ return; } void apc_windows_cs_lock(apc_windows_cs_rwlock_t *lock) { AcquireSRWLockExclusive(lock); } void apc_windows_cs_rdlock(apc_windows_cs_rwlock_t *lock) { AcquireSRWLockShared(lock); } void apc_windows_cs_unlock_rd(apc_windows_cs_rwlock_t *lock) { ReleaseSRWLockShared(lock); } void apc_windows_cs_unlock_wr(apc_windows_cs_rwlock_t *lock) { ReleaseSRWLockExclusive(lock); } #endif /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim>600: noexpandtab sw=4 ts=4 sts=4 fdm=marker * vim<600: noexpandtab sw=4 ts=4 sts=4 */ apcu-5.1.23/apc_windows_srwlock_kernel.h0000664000175000017500000000346314523735540017320 0ustar nikicnikic/* +----------------------------------------------------------------------+ | APC | +----------------------------------------------------------------------+ | Copyright (c) 2006-2011 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP 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.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Authors: Pierre Joye | +----------------------------------------------------------------------+ */ #ifndef APC_WINDOWS_CS_RWLOCK_H #define APC_WINDOWS_CS_RWLOCK_H #include "apc.h" #ifdef APC_SRWLOCK_KERNEL typedef SRWLOCK apc_windows_cs_rwlock_t; apc_windows_cs_rwlock_t *apc_windows_cs_create(apc_windows_cs_rwlock_t *lock); void apc_windows_cs_destroy(apc_windows_cs_rwlock_t *lock); void apc_windows_cs_lock(apc_windows_cs_rwlock_t *lock); void apc_windows_cs_rdlock(apc_windows_cs_rwlock_t *lock); void apc_windows_cs_unlock_rd(apc_windows_cs_rwlock_t *lock); void apc_windows_cs_unlock_wr(apc_windows_cs_rwlock_t *lock); #endif #endif /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim>600: noexpandtab sw=4 ts=4 sts=4 fdm=marker * vim<600: noexpandtab sw=4 ts=4 sts=4 */ apcu-5.1.23/apc_serializer.h0000664000175000017500000000573114523735540014673 0ustar nikicnikic/* +----------------------------------------------------------------------+ | APC | +----------------------------------------------------------------------+ | Copyright (c) 2006-2011 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP 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.php.net/license/3_01.txt. | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Authors: Gopal Vijayaraghavan | +----------------------------------------------------------------------+ */ #ifndef APC_SERIALIZER_H #define APC_SERIALIZER_H /* this is a shipped .h file, do not include any other header in this file */ #define APC_SERIALIZER_NAME(module) module##_apc_serializer #define APC_UNSERIALIZER_NAME(module) module##_apc_unserializer #define APC_SERIALIZER_ARGS unsigned char **buf, size_t *buf_len, const zval *value, void *config #define APC_UNSERIALIZER_ARGS zval *value, unsigned char *buf, size_t buf_len, void *config typedef int (*apc_serialize_t)(APC_SERIALIZER_ARGS); typedef int (*apc_unserialize_t)(APC_UNSERIALIZER_ARGS); typedef int (*apc_register_serializer_t)(const char* name, apc_serialize_t serialize, apc_unserialize_t unserialize, void *config); /* * ABI version for constant hooks. Increment this any time you make any changes * to any function in this file. */ #define APC_SERIALIZER_ABI "0" #define APC_SERIALIZER_CONSTANT "\000apc_register_serializer-" APC_SERIALIZER_ABI #if !defined(APC_UNUSED) # if defined(__GNUC__) # define APC_UNUSED __attribute__((unused)) # else # define APC_UNUSED # endif #endif static APC_UNUSED int apc_register_serializer( const char* name, apc_serialize_t serialize, apc_unserialize_t unserialize, void *config) { int retval = 0; zend_string *lookup = zend_string_init( APC_SERIALIZER_CONSTANT, sizeof(APC_SERIALIZER_CONSTANT)-1, 0); zval *magic = zend_get_constant(lookup); /* zend_get_constant will return 1 on success, otherwise apc_magic_constant wouldn't be touched at all */ if (magic) { apc_register_serializer_t register_func = (apc_register_serializer_t)(Z_LVAL_P(magic)); if(register_func) { retval = register_func(name, serialize, unserialize, NULL); } } zend_string_release(lookup); return retval; } #endif /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim>600: noexpandtab sw=4 ts=4 sts=4 fdm=marker * vim<600: noexpandtab sw=4 ts=4 sts=4 */ apcu-5.1.23/config.m40000664000175000017500000002343514523735540013236 0ustar nikicnikicPHP_ARG_ENABLE(apcu, whether to enable APCu support, [ --enable-apcu Enable APCu support]) AC_MSG_CHECKING(if APCu should be allowed to use rwlocks) AC_ARG_ENABLE(apcu-rwlocks, [ --disable-apcu-rwlocks Disable rwlocks in APCu], [ PHP_APCU_RWLOCKS=$enableval AC_MSG_RESULT($enableval) ], [ PHP_APCU_RWLOCKS=yes AC_MSG_RESULT(yes) ]) AC_MSG_CHECKING(if APCu should be built in debug mode) AC_ARG_ENABLE(apcu-debug, [ --enable-apcu-debug Enable APCu debugging], [ PHP_APCU_DEBUG=$enableval ], [ PHP_APCU_DEBUG=no ]) AC_MSG_RESULT($PHP_APCU_DEBUG) AC_MSG_CHECKING(if APCu should clear on SIGUSR1) AC_ARG_ENABLE(apcu-clear-signal, [ --enable-apcu-clear-signal Enable SIGUSR1 clearing handler], [ AC_DEFINE(APC_CLEAR_SIGNAL, 1, [ ]) AC_MSG_RESULT(yes) ], [ AC_MSG_RESULT(no) ]) PHP_APCU_MMAP=yes AC_MSG_CHECKING([if APCu will use mmap (or shm)]) AC_ARG_ENABLE(apcu-mmap, [ --disable-apcu-mmap Disable mmap, falls back on shm], [ if test "x$enableval" = "xno"; then PHP_APCU_MMAP=no else PHP_APCU_MMAP=yes fi ]) AC_MSG_RESULT($PHP_APCU_MMAP) PHP_APCU_SPINLOCK=no AC_MSG_CHECKING(if APCu should utilize spinlocks before flocks) AC_ARG_ENABLE(apcu-spinlocks, [ --enable-apcu-spinlocks Use spinlocks before flocks], [ if test "x$enableval" = "xno"; then PHP_APCU_SPINLOCK=no else PHP_APCU_SPINLOCK=yes fi ]) AC_MSG_RESULT($PHP_APCU_SPINLOCK) if test "$PHP_APCU_RWLOCKS" != "no"; then AC_CACHE_CHECK([whether the target compiler supports builtin atomics], PHP_cv_APCU_GCC_ATOMICS, [ AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[ int foo = 0; __sync_add_and_fetch(&foo, 1); __sync_sub_and_fetch(&foo, 1); return 0; ]])],[PHP_cv_APCU_GCC_ATOMICS=yes],[PHP_cv_APCU_GCC_ATOMICS=no]) ]) if test "x${PHP_cv_APCU_GCC_ATOMICS}" != "xyes"; then AC_MSG_ERROR([Compiler does not support atomics]) fi fi if test "$PHP_APCU" != "no"; then if test "$PHP_APCU_DEBUG" != "no"; then AC_DEFINE(APC_DEBUG, 1, [ ]) fi if test "$PHP_APCU_MMAP" != "no"; then AC_DEFINE(APC_MMAP, 1, [ ]) fi if test "$PHP_APCU_RWLOCKS" != "no"; then orig_LIBS="$LIBS" LIBS="$LIBS -lpthread" AC_MSG_CHECKING([for pthread rwlocks]) AC_RUN_IFELSE([AC_LANG_SOURCE([[ #include #include #include int main() { pthread_rwlock_t rwlock; pthread_rwlockattr_t attr; if(pthread_rwlockattr_init(&attr)) { puts("Unable to initialize pthread attributes (pthread_rwlockattr_init)."); return -1; } if(pthread_rwlockattr_setpshared(&attr, PTHREAD_PROCESS_SHARED)) { puts("Unable to set PTHREAD_PROCESS_SHARED (pthread_rwlockattr_setpshared), your system may not support shared rwlock's."); return -1; } if(pthread_rwlock_init(&rwlock, &attr)) { puts("Unable to initialize the rwlock (pthread_rwlock_init)."); return -1; } if(pthread_rwlockattr_destroy(&attr)) { puts("Unable to destroy rwlock attributes (pthread_rwlockattr_destroy)."); return -1; } if(pthread_rwlock_destroy(&rwlock)) { puts("Unable to destroy rwlock (pthread_rwlock_destroy)."); return -1; } return 0; } ]])],[ dnl -Success- APCU_CFLAGS="-D_GNU_SOURCE -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1" PHP_ADD_LIBRARY(pthread) PHP_LDFLAGS="$PHP_LDFLAGS -lpthread" AC_DEFINE(APC_NATIVE_RWLOCK, 1, [ ]) AC_MSG_RESULT([yes]) ],[ dnl -Failure- AC_MSG_RESULT([no]) PHP_APCU_RWLOCKS=no ],[ APCU_CFLAGS="-D_GNU_SOURCE -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1" PHP_ADD_LIBRARY(pthread) PHP_LDFLAGS="$PHP_LDFLAGS -lpthread" ]) LIBS="$orig_LIBS" fi if test "$PHP_APCU" != "no"; then orig_LIBS="$LIBS" LIBS="$LIBS -lpthread" AC_MSG_CHECKING([for pthread mutexes]) AC_RUN_IFELSE([AC_LANG_SOURCE([[ #include #include #include int main() { pthread_mutex_t mutex; pthread_mutexattr_t attr; if(pthread_mutexattr_init(&attr)) { puts("Unable to initialize pthread attributes (pthread_mutexattr_init)."); return -1; } if(pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED)) { puts("Unable to set PTHREAD_PROCESS_SHARED (pthread_mutexattr_setpshared), your system may not support shared mutex's."); return -1; } if(pthread_mutex_init(&mutex, &attr)) { puts("Unable to initialize the mutex (pthread_mutex_init)."); return -1; } if(pthread_mutexattr_destroy(&attr)) { puts("Unable to destroy mutex attributes (pthread_mutexattr_destroy)."); return -1; } if(pthread_mutex_destroy(&mutex)) { puts("Unable to destroy mutex (pthread_mutex_destroy)."); return -1; } return 0; } ]])],[ dnl -Success- APCU_CFLAGS="-D_GNU_SOURCE -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1" PHP_ADD_LIBRARY(pthread) PHP_LDFLAGS="$PHP_LDFLAGS -lpthread" AC_MSG_RESULT([yes]) AC_DEFINE(APC_HAS_PTHREAD_MUTEX, 1, [ ]) ],[ dnl -Failure- AC_MSG_RESULT([no]) PHP_APCU_MUTEX=no ],[ APCU_CFLAGS="-D_GNU_SOURCE -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1" PHP_ADD_LIBRARY(pthread) PHP_LDFLAGS="$PHP_LDFLAGS -lpthread" ]) LIBS="$orig_LIBS" fi if test "$PHP_APCU_RWLOCKS" = "no"; then if test "$PHP_APCU_MUTEX" = "no"; then if test "$PHP_APCU_SPINLOCK" != "no"; then AC_DEFINE(APC_SPIN_LOCK, 1, [ ]) AC_MSG_WARN([APCu spin locking enabled]) else AC_DEFINE(APC_FCNTL_LOCK, 1, [ ]) AC_MSG_WARN([APCu file locking enabled]) fi fi fi AC_CHECK_FUNCS(sigaction) AC_CACHE_CHECK(for union semun, php_cv_semun, [ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include #include #include ]], [[union semun x; x.val=1]])],[ php_cv_semun=yes ],[ php_cv_semun=no ]) ]) if test "$php_cv_semun" = "yes"; then AC_DEFINE(HAVE_SEMUN, 1, [ ]) else AC_DEFINE(HAVE_SEMUN, 0, [ ]) fi AC_ARG_ENABLE(valgrind-checks, [ --disable-valgrind-checks Disable valgrind based memory checks], [ PHP_APCU_VALGRIND=no ], [ PHP_APCU_VALGRIND=yes AC_CHECK_HEADER(valgrind/memcheck.h, [AC_DEFINE([HAVE_VALGRIND_MEMCHECK_H],1, [enable valgrind memchecks])]) ]) for i in -Wall -Wextra -Wno-unused-parameter; do AX_CHECK_COMPILE_FLAG([$i], [APCU_CFLAGS="$APCU_CFLAGS $i"]) done apc_sources="apc.c apc_lock.c apc_mutex.c php_apc.c \ apc_cache.c \ apc_mmap.c \ apc_shm.c \ apc_sma.c \ apc_stack.c \ apc_signal.c \ apc_time.c \ apc_iterator.c \ apc_persist.c" PHP_CHECK_LIBRARY(rt, shm_open, [PHP_ADD_LIBRARY(rt,,APCU_SHARED_LIBADD)]) PHP_NEW_EXTENSION(apcu, $apc_sources, $ext_shared,, \\$(APCU_CFLAGS)) PHP_SUBST(APCU_SHARED_LIBADD) PHP_SUBST(APCU_CFLAGS) PHP_SUBST(PHP_LDFLAGS) PHP_INSTALL_HEADERS(ext/apcu, [php_apc.h apc.h apc_api.h apc_cache.h apc_globals.h apc_iterator.h apc_lock.h apc_mutex.h apc_sma.h apc_serializer.h apc_stack.h apc_arginfo.h php_apc_legacy_arginfo.h]) AC_DEFINE(HAVE_APCU, 1, [ ]) fi PHP_ARG_ENABLE(coverage, whether to include code coverage symbols, [ --enable-coverage DEVELOPERS ONLY!!], no, no) if test "$PHP_COVERAGE" = "yes"; then if test "$GCC" != "yes"; then AC_MSG_ERROR([GCC is required for --enable-coverage]) fi dnl Check if ccache is being used case `$php_shtool path $CC` in *ccache*[)] gcc_ccache=yes;; *[)] gcc_ccache=no;; esac if test "$gcc_ccache" = "yes" && (test -z "$CCACHE_DISABLE" || test "$CCACHE_DISABLE" != "1"); then AC_MSG_ERROR([ccache must be disabled when --enable-coverage option is used. You can disable ccache by setting environment variable CCACHE_DISABLE=1.]) fi lcov_version_list="1.5 1.6 1.7 1.9" AC_CHECK_PROG(LCOV, lcov, lcov) AC_CHECK_PROG(GENHTML, genhtml, genhtml) PHP_SUBST(LCOV) PHP_SUBST(GENHTML) if test "$LCOV"; then AC_CACHE_CHECK([for lcov version], php_cv_lcov_version, [ php_cv_lcov_version=invalid lcov_version=`$LCOV -v 2>/dev/null | $SED -e 's/^.* //'` #' for lcov_check_version in $lcov_version_list; do if test "$lcov_version" = "$lcov_check_version"; then php_cv_lcov_version="$lcov_check_version (ok)" fi done ]) else lcov_msg="To enable code coverage reporting you must have one of the following LCOV versions installed: $lcov_version_list" AC_MSG_ERROR([$lcov_msg]) fi case $php_cv_lcov_version in ""|invalid[)] lcov_msg="You must have one of the following versions of LCOV: $lcov_version_list (found: $lcov_version)." AC_MSG_ERROR([$lcov_msg]) LCOV="exit 0;" ;; esac if test -z "$GENHTML"; then AC_MSG_ERROR([Could not find genhtml from the LCOV package]) fi PHP_ADD_MAKEFILE_FRAGMENT dnl Remove all optimization flags from CFLAGS changequote({,}) CFLAGS=`echo "$CFLAGS" | $SED -e 's/-O[0-9s]*//g'` CXXFLAGS=`echo "$CXXFLAGS" | $SED -e 's/-O[0-9s]*//g'` changequote([,]) dnl Add the special gcc flags CFLAGS="$CFLAGS -O0 -ggdb -fprofile-arcs -ftest-coverage" CXXFLAGS="$CXXFLAGS -ggdb -O0 -fprofile-arcs -ftest-coverage" fi dnl vim: set ts=2 apcu-5.1.23/config.w320000664000175000017500000000205214523735540013321 0ustar nikicnikic// vim:ft=javascript ARG_ENABLE('apcu', 'Whether to enable APCu support', 'no'); ARG_ENABLE('apcu-debug', 'Whether to enable APCu debugging', 'no'); if(PHP_APCU != 'no') { var apc_sources = 'apc.c apc_lock.c apc_windows_srwlock_kernel.c php_apc.c ' + 'apc_cache.c ' + 'apc_mmap.c ' + 'apc_shm.c ' + 'apc_sma.c ' + 'apc_stack.c ' + 'apc_signal.c ' + 'apc_time.c ' + 'apc_iterator.c ' + 'apc_persist.c'; if(PHP_APCU_DEBUG != 'no') { ADD_FLAG('CFLAGS_APC', '/D APC_DEBUG=1'); } /* XXX srwlock kernel as most BC compatible for now */ AC_DEFINE('APC_SRWLOCK_KERNEL', 1); AC_DEFINE('HAVE_APCU', 1); ADD_FLAG('CFLAGS_APCU', '/D WIN32_ONLY_COMPILER=1 /DAPC_SRWLOCK_KERNEL=1'); PHP_INSTALL_HEADERS("ext/apcu", "php_apc.h apc.h apc_api.h apc_cache.h apc_globals.h apc_iterator.h apc_lock.h apc_mutex.h apc_sma.h apc_serializer.h apc_stack.h apc_windows_srwlock_kernel.h apc_arginfo.h php_apc_legacy_arginfo.h"); EXTENSION('apcu', apc_sources, PHP_APCU_SHARED, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1"); } apcu-5.1.23/LICENSE0000664000175000017500000000622214523735540012527 0ustar nikicnikic-------------------------------------------------------------------- The PHP License, version 3.01 Copyright (c) 1999 - 2014 The PHP Group. All rights reserved. -------------------------------------------------------------------- Redistribution and use in source and binary forms, with or without modification, is permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name "PHP" must not be used to endorse or promote products derived from this software without prior written permission. For written permission, please contact group@php.net. 4. Products derived from this software may not be called "PHP", nor may "PHP" appear in their name, without prior written permission from group@php.net. You may indicate that your software works in conjunction with PHP by saying "Foo for PHP" instead of calling it "PHP Foo" or "phpfoo" 5. The PHP Group may publish revised and/or new versions of the license from time to time. Each version will be given a distinguishing version number. Once covered code has been published under a particular version of the license, you may always continue to use it under the terms of that version. You may also choose to use such covered code under the terms of any subsequent version of the license published by the PHP Group. No one other than the PHP Group has the right to modify the terms applicable to covered code created under this License. 6. Redistributions of any form whatsoever must retain the following acknowledgment: "This product includes PHP software, freely available from ". THIS SOFTWARE IS PROVIDED BY THE PHP DEVELOPMENT TEAM ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PHP DEVELOPMENT TEAM OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------- This software consists of voluntary contributions made by many individuals on behalf of the PHP Group. The PHP Group can be contacted via Email at group@php.net. For more information on the PHP Group and the PHP project, please see . PHP includes the Zend Engine, freely available at . apcu-5.1.23/Makefile.frag0000664000175000017500000000041614523735540014077 0ustar nikicnikicclean-coverage: @rm -fr .coverage coverage coverage: test clean-coverage @echo "Generating $@" @$(LCOV) --directory . --capture --base-directory=. --output-file .coverage @$(GENHTML) --legend --output-directory coverage/ --title "pecl/apc code coverage" .coverage apcu-5.1.23/NOTICE0000664000175000017500000000331214523735540012423 0ustar nikicnikicThis is the NOTICE file that holds acknowledgements and stuff. The Alternative PHP Cache (APC) is a free and open opcode cache for PHP. This extension is being released under the PHP License for complete compliance with PHP and to encourage wide-spread use. It is our intention that this project be kept open source and that all commercial spin-offs contribute their modifications back into the public source-tree. Creators: Daniel Cowgill George Schlossnagle PHP5 support and major features by: Arun C. Murthy Gopal Vijayaraghavan Rasmus Lerdorf This software was contributed to PHP by Community Connect Inc. in 2002 and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1. Future revisions and derivatives of this source code must acknowledge Community Connect Inc. as the original contributor of this module by leaving this note intact in the source code. All other licensing and usage conditions are those of the PHP Group. We would like to thank Community Connect Inc. and Yahoo! Inc. for supporting this project and providing a challenging and stimulating environment in which exciting projects can happen. Contributors: Mike Bretz bug fixes, GUI, and lots of work Ricardo Galli changed read-write locks to prefer readers Yann Grossel bug fixes Thies Arntzen bug fixes Sara Golemon optimizer work Special Thanks: Florian Baumert help debugging phplib problems Thomas Duffey help debugging inheritance issues Vibol Hou help debugging phplib problems Angel Li diffs for ANSI comment compliance Christian Rishøj help debugging phplib problems Sascha Schumann memory error bug fix apcu-5.1.23/php74_shim.h0000664000175000017500000001027714523735540013662 0ustar nikicnikic#ifndef PHP74_SHIM_H #define PHP74_SHIM_H #if PHP_VERSION_ID < 70400 #define ZEND_TRY_ASSIGN_NULL(zv) do { \ ZVAL_DEREF(zv); \ zval_ptr_dtor(zv); \ ZVAL_NULL(zv); \ } while (0) #define ZEND_TRY_ASSIGN_REF_NULL(zv) do { \ ZEND_ASSERT(Z_ISREF_P(zv)); \ ZEND_TRY_ASSIGN_NULL(zv); \ } while (0) #define ZEND_TRY_ASSIGN_FALSE(zv) do { \ ZVAL_DEREF(zv); \ zval_ptr_dtor(zv); \ ZVAL_FALSE(zv); \ } while (0) #define ZEND_TRY_ASSIGN_REF_FALSE(zv) do { \ ZEND_ASSERT(Z_ISREF_P(zv)); \ ZEND_TRY_ASSIGN_FALSE(zv); \ } while (0) #define ZEND_TRY_ASSIGN_TRUE(zv) do { \ ZVAL_DEREF(zv); \ zval_ptr_dtor(zv); \ ZVAL_TRUE(zv); \ } while (0) #define ZEND_TRY_ASSIGN_REF_TRUE(zv) do { \ ZEND_ASSERT(Z_ISREF_P(zv)); \ ZEND_TRY_ASSIGN_TRUE(zv); \ } while (0) #define ZEND_TRY_ASSIGN_BOOL(zv, bval) do { \ ZVAL_DEREF(zv); \ zval_ptr_dtor(zv); \ ZVAL_BOOL(zv, bval); \ } while (0) #define ZEND_TRY_ASSIGN_REF_BOOL(zv, bval) do { \ ZEND_ASSERT(Z_ISREF_P(zv)); \ ZEND_TRY_ASSIGN_BOOL(zv, bval); \ } while (0) #define ZEND_TRY_ASSIGN_LONG(zv, lval) do { \ ZVAL_DEREF(zv); \ zval_ptr_dtor(zv); \ ZVAL_LONG(zv, lval); \ } while (0) #define ZEND_TRY_ASSIGN_REF_LONG(zv, lval) do { \ ZEND_ASSERT(Z_ISREF_P(zv)); \ ZEND_TRY_ASSIGN_LONG(zv, lval); \ } while (0) #define ZEND_TRY_ASSIGN_DOUBLE(zv, dval) do { \ ZVAL_DEREF(zv); \ zval_ptr_dtor(zv); \ ZVAL_DOUBLE(zv, dval); \ } while (0) #define ZEND_TRY_ASSIGN_REF_DOUBLE(zv, dval) do { \ ZEND_ASSERT(Z_ISREF_P(zv)); \ ZEND_TRY_ASSIGN_DOUBLE(zv, dval); \ } while (0) #define ZEND_TRY_ASSIGN_EMPTY_STRING(zv) do { \ ZVAL_DEREF(zv); \ zval_ptr_dtor(zv); \ ZVAL_EMPTY_STRING(zv); \ } while (0) #define ZEND_TRY_ASSIGN_REF_EMPTY_STRING(zv) do { \ ZEND_ASSERT(Z_ISREF_P(zv)); \ ZEND_TRY_ASSIGN_EMPTY_STRING(zv); \ } while (0) #define ZEND_TRY_ASSIGN_STR(zv, str) do { \ ZVAL_DEREF(zv); \ zval_ptr_dtor(zv); \ ZVAL_STR(zv, str); \ } while (0) #define ZEND_TRY_ASSIGN_REF_STR(zv, str) do { \ ZEND_ASSERT(Z_ISREF_P(zv)); \ ZEND_TRY_ASSIGN_STR(zv, str); \ } while (0) #define ZEND_TRY_ASSIGN_NEW_STR(zv, str) do { \ ZVAL_DEREF(zv); \ zval_ptr_dtor(zv); \ ZVAL_NEW_STR(zv, str); \ } while (0) #define ZEND_TRY_ASSIGN_REF_NEW_STR(zv, str) do { \ ZEND_ASSERT(Z_ISREF_P(zv)); \ ZEND_TRY_ASSIGN_NEW_STR(zv, str); \ } while (0) #define ZEND_TRY_ASSIGN_STRING(zv, string) do { \ ZVAL_DEREF(zv); \ zval_ptr_dtor(zv); \ ZVAL_STRING(zv, string); \ } while (0) #define ZEND_TRY_ASSIGN_REF_STRING(zv, string) do { \ ZEND_ASSERT(Z_ISREF_P(zv)); \ ZEND_TRY_ASSIGN_STRING(zv, string); \ } while (0) #define ZEND_TRY_ASSIGN_STRINGL(zv, string, len) do { \ ZVAL_DEREF(zv); \ zval_ptr_dtor(zv); \ ZVAL_STRINGL(zv, string, len); \ } while (0) #define ZEND_TRY_ASSIGN_REF_STRINGL(zv, string, len) do { \ ZEND_ASSERT(Z_ISREF_P(zv)); \ ZEND_TRY_ASSIGN_STRINGL(zv, string, len); \ } while (0) #define ZEND_TRY_ASSIGN_ARR(zv, arr) do { \ ZVAL_DEREF(zv); \ zval_ptr_dtor(zv); \ ZVAL_ARR(zv, arr); \ } while (0) #define ZEND_TRY_ASSIGN_REF_ARR(zv, arr) do { \ ZEND_ASSERT(Z_ISREF_P(zv)); \ ZEND_TRY_ASSIGN_ARR(zv, arr); \ } while (0) #define ZEND_TRY_ASSIGN_RES(zv, res) do { \ ZVAL_DEREF(zv); \ zval_ptr_dtor(zv); \ ZVAL_RES(zv, res); \ } while (0) #define ZEND_TRY_ASSIGN_REF_RES(zv, res) do { \ ZEND_ASSERT(Z_ISREF_P(zv)); \ ZEND_TRY_ASSIGN_RES(zv, res); \ } while (0) #define ZEND_TRY_ASSIGN_VALUE(zv, other_zv) do { \ ZVAL_DEREF(zv); \ zval_ptr_dtor(zv); \ ZVAL_COPY_VALUE(zv, other_zv); \ } while (0) #define ZEND_TRY_ASSIGN_REF_VALUE(zv, other_zv) do { \ ZEND_ASSERT(Z_ISREF_P(zv)); \ ZEND_TRY_ASSIGN_VALUE(zv, other_zv); \ } while (0) #define ZEND_TRY_ASSIGN_COPY(zv, other_zv) do { \ ZVAL_DEREF(zv); \ zval_ptr_dtor(zv); \ ZVAL_COPY(zv, other_zv); \ } while (0) #define ZEND_TRY_ASSIGN_REF_COPY(zv, other_zv) do { \ ZEND_ASSERT(Z_ISREF_P(zv)); \ ZEND_TRY_ASSIGN_COPY(zv, other_zv); \ } while (0) /* Initializes a reference to an empty array and returns dereferenced zval, * or NULL if the initialization failed. */ static zend_always_inline zval *zend_try_array_init(zval *zv) { ZVAL_DEREF(zv); array_init(zv); return zv; } static zend_always_inline zval *zend_try_array_init_size(zval *zv, uint32_t size) { ZVAL_DEREF(zv); array_init_size(zv, size); return zv; } #endif #endif apcu-5.1.23/php_apc.c0000664000175000017500000005357014523735540013310 0ustar nikicnikic/* +----------------------------------------------------------------------+ | APC | +----------------------------------------------------------------------+ | Copyright (c) 2006-2011 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP 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.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Authors: Daniel Cowgill | | Rasmus Lerdorf | +----------------------------------------------------------------------+ This software was contributed to PHP by Community Connect Inc. in 2002 and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1. Future revisions and derivatives of this source code must acknowledge Community Connect Inc. as the original contributor of this module by leaving this note intact in the source code. All other licensing and usage conditions are those of the PHP Group. */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include "apc_cache.h" #include "apc_iterator.h" #include "apc_sma.h" #include "apc_lock.h" #include "apc_mutex.h" #include "apc_strings.h" #include "apc_time.h" #include "php_globals.h" #include "php_ini.h" #include "ext/standard/info.h" #include "ext/standard/file.h" #include "ext/standard/flock_compat.h" #include "ext/standard/md5.h" #include "ext/standard/php_var.h" #if PHP_VERSION_ID >= 80000 # include "php_apc_arginfo.h" #else # include "php_apc_legacy_arginfo.h" #endif #include "php74_shim.h" #ifdef HAVE_SYS_FILE_H #include #endif #include "SAPI.h" #include "php_apc.h" #if HAVE_SIGACTION #include "apc_signal.h" #endif /* {{{ ZEND_DECLARE_MODULE_GLOBALS(apcu) */ ZEND_DECLARE_MODULE_GLOBALS(apcu) /* True globals */ apc_cache_t* apc_user_cache = NULL; /* External APC SMA */ apc_sma_t apc_sma; #define X(str) zend_string *apc_str_ ## str; APC_STRINGS #undef X /* Global init functions */ static void php_apc_init_globals(zend_apcu_globals* apcu_globals) { apcu_globals->initialized = 0; apcu_globals->slam_defense = 0; apcu_globals->smart = 0; apcu_globals->preload_path = NULL; apcu_globals->coredump_unmap = 0; apcu_globals->use_request_time = 0; apcu_globals->serializer_name = NULL; apcu_globals->entry_level = 0; } /* }}} */ /* {{{ PHP_INI */ static PHP_INI_MH(OnUpdateShmSegments) /* {{{ */ { zend_long shm_segments = ZEND_STRTOL(new_value->val, NULL, 10); #if APC_MMAP if (shm_segments != 1) { php_error_docref(NULL, E_WARNING, "apc.shm_segments setting ignored in MMAP mode"); } APCG(shm_segments) = 1; #else APCG(shm_segments) = shm_segments; #endif return SUCCESS; } /* }}} */ static PHP_INI_MH(OnUpdateShmSize) /* {{{ */ { #if PHP_VERSION_ID >= 80200 zend_long s = zend_ini_parse_quantity_warn(new_value, entry->name); #else zend_long s = zend_atol(new_value->val, new_value->len); #endif if (s <= 0) { return FAILURE; } if (s < Z_L(1048576)) { /* if it's less than 1Mb, they are probably using the old syntax */ php_error_docref( NULL, E_WARNING, "apc.shm_size now uses M/G suffixes, please update your ini files"); s = s * Z_L(1048576); } APCG(shm_size) = s; return SUCCESS; } /* }}} */ PHP_INI_BEGIN() STD_PHP_INI_BOOLEAN("apc.enabled", "1", PHP_INI_SYSTEM, OnUpdateBool, enabled, zend_apcu_globals, apcu_globals) STD_PHP_INI_ENTRY("apc.shm_segments", "1", PHP_INI_SYSTEM, OnUpdateShmSegments, shm_segments, zend_apcu_globals, apcu_globals) STD_PHP_INI_ENTRY("apc.shm_size", "32M", PHP_INI_SYSTEM, OnUpdateShmSize, shm_size, zend_apcu_globals, apcu_globals) STD_PHP_INI_ENTRY("apc.entries_hint", "4096", PHP_INI_SYSTEM, OnUpdateLong, entries_hint, zend_apcu_globals, apcu_globals) STD_PHP_INI_ENTRY("apc.gc_ttl", "3600", PHP_INI_SYSTEM, OnUpdateLong, gc_ttl, zend_apcu_globals, apcu_globals) STD_PHP_INI_ENTRY("apc.ttl", "0", PHP_INI_SYSTEM, OnUpdateLong, ttl, zend_apcu_globals, apcu_globals) STD_PHP_INI_ENTRY("apc.smart", "0", PHP_INI_SYSTEM, OnUpdateLong, smart, zend_apcu_globals, apcu_globals) #if APC_MMAP STD_PHP_INI_ENTRY("apc.mmap_file_mask", NULL, PHP_INI_SYSTEM, OnUpdateString, mmap_file_mask, zend_apcu_globals, apcu_globals) #endif STD_PHP_INI_BOOLEAN("apc.enable_cli", "0", PHP_INI_SYSTEM, OnUpdateBool, enable_cli, zend_apcu_globals, apcu_globals) STD_PHP_INI_BOOLEAN("apc.slam_defense", "0", PHP_INI_SYSTEM, OnUpdateBool, slam_defense, zend_apcu_globals, apcu_globals) STD_PHP_INI_ENTRY("apc.preload_path", (char*)NULL, PHP_INI_SYSTEM, OnUpdateString, preload_path, zend_apcu_globals, apcu_globals) STD_PHP_INI_BOOLEAN("apc.coredump_unmap", "0", PHP_INI_SYSTEM, OnUpdateBool, coredump_unmap, zend_apcu_globals, apcu_globals) STD_PHP_INI_BOOLEAN("apc.use_request_time", "0", PHP_INI_ALL, OnUpdateBool, use_request_time, zend_apcu_globals, apcu_globals) STD_PHP_INI_ENTRY("apc.serializer", "php", PHP_INI_SYSTEM, OnUpdateStringUnempty, serializer_name, zend_apcu_globals, apcu_globals) PHP_INI_END() /* }}} */ zend_bool apc_is_enabled(void) { return APCG(enabled); } /* {{{ PHP_MINFO_FUNCTION(apcu) */ static PHP_MINFO_FUNCTION(apcu) { php_info_print_table_start(); php_info_print_table_row(2, "APCu Support", APCG(enabled) ? "Enabled" : "Disabled"); php_info_print_table_row(2, "Version", PHP_APCU_VERSION); #ifdef APC_DEBUG php_info_print_table_row(2, "APCu Debugging", "Enabled"); #else php_info_print_table_row(2, "APCu Debugging", "Disabled"); #endif #if APC_MMAP php_info_print_table_row(2, "MMAP Support", "Enabled"); php_info_print_table_row(2, "MMAP File Mask", APCG(mmap_file_mask)); #else php_info_print_table_row(2, "MMAP Support", "Disabled"); #endif if (APCG(enabled)) { apc_serializer_t *serializer = NULL; smart_str names = {0,}; int i; for( i = 0, serializer = apc_get_serializers(); serializer->name != NULL; serializer++, i++) { if (i != 0) { smart_str_appends(&names, ", "); } smart_str_appends(&names, serializer->name); } if (names.s) { smart_str_0(&names); php_info_print_table_row(2, "Serialization Support", names.s->val); smart_str_free(&names); } else { php_info_print_table_row(2, "Serialization Support", "Broken"); } } else { php_info_print_table_row(2, "Serialization Support", "Disabled"); } php_info_print_table_row(2, "Build Date", __DATE__ " " __TIME__); php_info_print_table_end(); DISPLAY_INI_ENTRIES(); } /* }}} */ /* {{{ PHP_MINIT_FUNCTION(apcu) */ static PHP_MINIT_FUNCTION(apcu) { #if defined(ZTS) && defined(COMPILE_DL_APCU) ZEND_TSRMLS_CACHE_UPDATE(); #endif ZEND_INIT_MODULE_GLOBALS(apcu, php_apc_init_globals, NULL); REGISTER_INI_ENTRIES(); #define X(str) \ apc_str_ ## str = zend_new_interned_string( \ zend_string_init(#str, sizeof(#str) - 1, 1)); APC_STRINGS #undef X /* locks initialized regardless of settings */ apc_lock_init(); APC_MUTEX_INIT(); /* Disable APC in cli mode unless overridden by apc.enable_cli */ if (!APCG(enable_cli) && !strcmp(sapi_module.name, "cli")) { APCG(enabled) = 0; } /* only run initialization if APC is enabled */ if (APCG(enabled)) { if (!APCG(initialized)) { #if APC_MMAP char *mmap_file_mask = APCG(mmap_file_mask); #else char *mmap_file_mask = NULL; #endif /* ensure this runs only once */ APCG(initialized) = 1; /* initialize shared memory allocator */ apc_sma_init( &apc_sma, (void **) &apc_user_cache, (apc_sma_expunge_f) apc_cache_default_expunge, APCG(shm_segments), APCG(shm_size), mmap_file_mask); REGISTER_LONG_CONSTANT(APC_SERIALIZER_CONSTANT, (zend_long)&_apc_register_serializer, CONST_PERSISTENT | CONST_CS); /* register default serializer */ _apc_register_serializer( "php", APC_SERIALIZER_NAME(php), APC_UNSERIALIZER_NAME(php), NULL); /* test out the constant function pointer */ assert(apc_get_serializers()->name != NULL); /* create user cache */ apc_user_cache = apc_cache_create( &apc_sma, apc_find_serializer(APCG(serializer_name)), APCG(entries_hint), APCG(gc_ttl), APCG(ttl), APCG(smart), APCG(slam_defense)); /* preload data from path specified in configuration */ if (APCG(preload_path)) { apc_cache_preload( apc_user_cache, APCG(preload_path)); } } } /* initialize iterator object */ apc_iterator_init(module_number); return SUCCESS; } /* }}} */ /* {{{ PHP_MSHUTDOWN_FUNCTION(apcu) */ static PHP_MSHUTDOWN_FUNCTION(apcu) { #define X(str) zend_string_release(apc_str_ ## str); APC_STRINGS #undef X /* locks shutdown regardless of settings */ apc_lock_cleanup(); APC_MUTEX_CLEANUP(); /* only shut down if APC is enabled */ if (APCG(enabled)) { if (APCG(initialized)) { /* Detach cache and shared memory allocator from shared memory. */ apc_cache_detach(apc_user_cache); apc_sma_detach(&apc_sma); APCG(initialized) = 0; } #if HAVE_SIGACTION apc_shutdown_signals(); #endif } apc_iterator_shutdown(module_number); UNREGISTER_INI_ENTRIES(); return SUCCESS; } /* }}} */ /* {{{ PHP_RINIT_FUNCTION(apcu) */ static PHP_RINIT_FUNCTION(apcu) { #if defined(ZTS) && defined(COMPILE_DL_APCU) ZEND_TSRMLS_CACHE_UPDATE(); #endif APCG(request_time) = 0; if (APCG(enabled)) { if (APCG(serializer_name)) { /* Avoid race conditions between MINIT of apc and serializer exts like igbinary */ apc_cache_serializer(apc_user_cache, APCG(serializer_name)); } #if HAVE_SIGACTION apc_set_signals(); #endif } return SUCCESS; } /* }}} */ /* {{{ proto void apcu_clear_cache() */ PHP_FUNCTION(apcu_clear_cache) { if (zend_parse_parameters_none() == FAILURE) { return; } apc_cache_clear(apc_user_cache); RETURN_TRUE; } /* }}} */ /* {{{ proto array apcu_cache_info([bool limited]) */ PHP_FUNCTION(apcu_cache_info) { zend_bool limited = 0; ZEND_PARSE_PARAMETERS_START(0,1) Z_PARAM_OPTIONAL Z_PARAM_BOOL(limited) ZEND_PARSE_PARAMETERS_END(); if (!apc_cache_info(return_value, apc_user_cache, limited)) { php_error_docref(NULL, E_WARNING, "No APC info available. Perhaps APC is not enabled? Check apc.enabled in your ini file"); RETURN_FALSE; } } /* }}} */ /* {{{ proto array apcu_key_info(string key) */ PHP_FUNCTION(apcu_key_info) { zend_string *key; ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_STR(key) ZEND_PARSE_PARAMETERS_END(); apc_cache_stat(apc_user_cache, key, return_value); } /* }}} */ /* {{{ proto array apcu_sma_info([bool limited]) */ PHP_FUNCTION(apcu_sma_info) { apc_sma_info_t* info; zval block_lists; int i; zend_bool limited = 0; ZEND_PARSE_PARAMETERS_START(0, 1) Z_PARAM_OPTIONAL Z_PARAM_BOOL(limited) ZEND_PARSE_PARAMETERS_END(); info = apc_sma_info(&apc_sma, limited); if (!info) { php_error_docref(NULL, E_WARNING, "No APC SMA info available. Perhaps APC is disabled via apc.enabled?"); RETURN_FALSE; } array_init(return_value); add_assoc_long(return_value, "num_seg", info->num_seg); add_assoc_double(return_value, "seg_size", (double)info->seg_size); add_assoc_double(return_value, "avail_mem", (double)apc_sma_get_avail_mem(&apc_sma)); if (limited) { apc_sma_free_info(&apc_sma, info); return; } array_init(&block_lists); for (i = 0; i < info->num_seg; i++) { apc_sma_link_t* p; zval list; array_init(&list); for (p = info->list[i]; p != NULL; p = p->next) { zval link; array_init(&link); add_assoc_long(&link, "size", p->size); add_assoc_long(&link, "offset", p->offset); add_next_index_zval(&list, &link); } add_next_index_zval(&block_lists, &list); } add_assoc_zval(return_value, "block_lists", &block_lists); apc_sma_free_info(&apc_sma, info); } /* }}} */ /* {{{ php_apc_update */ zend_bool php_apc_update( zend_string *key, apc_cache_atomic_updater_t updater, void *data, zend_bool insert_if_not_found, time_t ttl) { if (APCG(serializer_name)) { /* Avoid race conditions between MINIT of apc and serializer exts like igbinary */ apc_cache_serializer(apc_user_cache, APCG(serializer_name)); } return apc_cache_atomic_update_long(apc_user_cache, key, updater, data, insert_if_not_found, ttl); } /* }}} */ /* {{{ apc_store_helper(INTERNAL_FUNCTION_PARAMETERS, const zend_bool exclusive) */ static void apc_store_helper(INTERNAL_FUNCTION_PARAMETERS, const zend_bool exclusive) { zval *key; zval *val = NULL; zend_long ttl = 0L; ZEND_PARSE_PARAMETERS_START(1, 3) Z_PARAM_ZVAL(key) Z_PARAM_OPTIONAL Z_PARAM_ZVAL(val) Z_PARAM_LONG(ttl) ZEND_PARSE_PARAMETERS_END(); if (APCG(serializer_name)) { /* Avoid race conditions between MINIT of apc and serializer exts like igbinary */ apc_cache_serializer(apc_user_cache, APCG(serializer_name)); } /* TODO: Port to array|string for PHP 8? */ if (Z_TYPE_P(key) == IS_ARRAY) { zval *hentry; zend_string *hkey; zend_ulong hkey_idx; HashTable* hash = Z_ARRVAL_P(key); /* We only insert keys that failed */ zval fail_zv; ZVAL_LONG(&fail_zv, -1); array_init(return_value); ZEND_HASH_FOREACH_KEY_VAL(hash, hkey_idx, hkey, hentry) { ZVAL_DEREF(hentry); if (hkey) { zend_string_addref(hkey); } else { hkey = zend_long_to_str(hkey_idx); } if (!apc_cache_store(apc_user_cache, hkey, hentry, (uint32_t) ttl, exclusive)) { zend_symtable_add_new(Z_ARRVAL_P(return_value), hkey, &fail_zv); } zend_string_release(hkey); } ZEND_HASH_FOREACH_END(); return; } else if (Z_TYPE_P(key) == IS_STRING) { if (!val) { /* nothing to store */ RETURN_FALSE; } RETURN_BOOL(apc_cache_store(apc_user_cache, Z_STR_P(key), val, (uint32_t) ttl, exclusive)); } else { apc_warning("apc_store expects key parameter to be a string or an array of key/value pairs."); RETURN_FALSE; } } /* }}} */ /* {{{ proto bool apcu_enabled(void) returns true when apcu is usable in the current environment */ PHP_FUNCTION(apcu_enabled) { if (zend_parse_parameters_none() == FAILURE) { return; } RETURN_BOOL(APCG(enabled)); } /* }}} */ /* {{{ proto int apcu_store(mixed key, mixed var [, long ttl ]) */ PHP_FUNCTION(apcu_store) { apc_store_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); } /* }}} */ /* {{{ proto int apcu_add(mixed key, mixed var [, long ttl ]) */ PHP_FUNCTION(apcu_add) { apc_store_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1); } /* }}} */ /* {{{ php_inc_updater */ struct php_inc_updater_args { zend_long step; zend_long rval; }; static zend_bool php_inc_updater(apc_cache_t *cache, zend_long *entry, void *data) { struct php_inc_updater_args *args = (struct php_inc_updater_args *) data; args->rval = ATOMIC_ADD(*entry, args->step); return 1; } /* {{{ proto long apcu_inc(string key [, long step [, bool& success [, long ttl]]]) */ PHP_FUNCTION(apcu_inc) { zend_string *key; struct php_inc_updater_args args; zend_long step = 1, ttl = 0; zval *success = NULL; ZEND_PARSE_PARAMETERS_START(1, 4) Z_PARAM_STR(key) Z_PARAM_OPTIONAL Z_PARAM_LONG(step) Z_PARAM_ZVAL(success) Z_PARAM_LONG(ttl) ZEND_PARSE_PARAMETERS_END(); args.step = step; if (php_apc_update(key, php_inc_updater, &args, 1, ttl)) { if (success) { ZEND_TRY_ASSIGN_REF_TRUE(success); } RETURN_LONG(args.rval); } if (success) { ZEND_TRY_ASSIGN_REF_FALSE(success); } RETURN_FALSE; } /* }}} */ /* {{{ proto long apcu_dec(string key [, long step [, bool &success [, long ttl]]]) */ PHP_FUNCTION(apcu_dec) { zend_string *key; struct php_inc_updater_args args; zend_long step = 1, ttl = 0; zval *success = NULL; ZEND_PARSE_PARAMETERS_START(1, 4) Z_PARAM_STR(key) Z_PARAM_OPTIONAL Z_PARAM_LONG(step) Z_PARAM_ZVAL(success) Z_PARAM_LONG(ttl) ZEND_PARSE_PARAMETERS_END(); args.step = 0 - step; if (php_apc_update(key, php_inc_updater, &args, 1, ttl)) { if (success) { ZEND_TRY_ASSIGN_REF_TRUE(success); } RETURN_LONG(args.rval); } if (success) { ZEND_TRY_ASSIGN_REF_FALSE(success); } RETURN_FALSE; } /* }}} */ /* {{{ php_cas_updater */ static zend_bool php_cas_updater(apc_cache_t *cache, zend_long *entry, void *data) { zend_long *vals = (zend_long *) data; zend_long old = vals[0]; zend_long new = vals[1]; return ATOMIC_CAS(*entry, old, new); } /* }}} */ /* {{{ proto int apcu_cas(string key, int old, int new) */ PHP_FUNCTION(apcu_cas) { zend_string *key; zend_long vals[2]; ZEND_PARSE_PARAMETERS_START(3, 3) Z_PARAM_STR(key) Z_PARAM_LONG(vals[0]) Z_PARAM_LONG(vals[1]) ZEND_PARSE_PARAMETERS_END(); if (APCG(serializer_name)) { /* Avoid race conditions between MINIT of apc and serializer exts like igbinary */ apc_cache_serializer(apc_user_cache, APCG(serializer_name)); } RETURN_BOOL(apc_cache_atomic_update_long(apc_user_cache, key, php_cas_updater, &vals, 0, 0)); } /* }}} */ /* {{{ proto mixed apcu_fetch(mixed key[, bool &success]) */ PHP_FUNCTION(apcu_fetch) { zval *key; zval *success = NULL; time_t t; int result; ZEND_PARSE_PARAMETERS_START(1, 2) Z_PARAM_ZVAL(key) Z_PARAM_OPTIONAL Z_PARAM_ZVAL(success) ZEND_PARSE_PARAMETERS_END(); t = apc_time(); if (Z_TYPE_P(key) != IS_STRING && Z_TYPE_P(key) != IS_ARRAY) { convert_to_string(key); } /* TODO: Port to array|string for PHP 8? */ if (Z_TYPE_P(key) == IS_STRING) { result = apc_cache_fetch(apc_user_cache, Z_STR_P(key), t, return_value); } else if (Z_TYPE_P(key) == IS_ARRAY) { zval *hentry; array_init(return_value); ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(key), hentry) { ZVAL_DEREF(hentry); if (Z_TYPE_P(hentry) == IS_STRING) { zval result_entry; ZVAL_UNDEF(&result_entry); if (apc_cache_fetch(apc_user_cache, Z_STR_P(hentry), t, &result_entry)) { zend_hash_update(Z_ARRVAL_P(return_value), Z_STR_P(hentry), &result_entry); } } else { apc_warning("apc_fetch() expects a string or array of strings."); } } ZEND_HASH_FOREACH_END(); result = 1; } else { apc_warning("apc_fetch() expects a string or array of strings."); result = 0; } if (success) { ZEND_TRY_ASSIGN_REF_BOOL(success, result); } if (!result) { RETURN_FALSE; } } /* }}} */ /* {{{ proto mixed apcu_exists(mixed key) */ PHP_FUNCTION(apcu_exists) { zval *key; time_t t; ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ZVAL(key) ZEND_PARSE_PARAMETERS_END(); t = apc_time(); if (Z_TYPE_P(key) != IS_STRING && Z_TYPE_P(key) != IS_ARRAY) { convert_to_string(key); } /* TODO: Port to array|string for PHP 8? */ if (Z_TYPE_P(key) == IS_STRING) { RETURN_BOOL(apc_cache_exists(apc_user_cache, Z_STR_P(key), t)); } else if (Z_TYPE_P(key) == IS_ARRAY) { zval *hentry; zval true_zv; ZVAL_TRUE(&true_zv); array_init(return_value); ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(key), hentry) { ZVAL_DEREF(hentry); if (Z_TYPE_P(hentry) == IS_STRING) { if (apc_cache_exists(apc_user_cache, Z_STR_P(hentry), t)) { zend_hash_add_new(Z_ARRVAL_P(return_value), Z_STR_P(hentry), &true_zv); } } else { apc_warning( "apc_exists() expects a string or array of strings."); } } ZEND_HASH_FOREACH_END(); } else { apc_warning("apc_exists() expects a string or array of strings."); RETURN_FALSE; } } /* }}} */ /* {{{ proto mixed apcu_delete(mixed keys) */ PHP_FUNCTION(apcu_delete) { zval *keys; ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ZVAL(keys) ZEND_PARSE_PARAMETERS_END(); if (Z_TYPE_P(keys) == IS_STRING) { RETURN_BOOL(apc_cache_delete(apc_user_cache, Z_STR_P(keys))); } else if (Z_TYPE_P(keys) == IS_ARRAY) { zval *hentry; array_init(return_value); ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(keys), hentry) { ZVAL_DEREF(hentry); if (Z_TYPE_P(hentry) != IS_STRING) { apc_warning("apc_delete() expects a string, array of strings, or APCIterator instance"); add_next_index_zval(return_value, hentry); Z_TRY_ADDREF_P(hentry); } else if (apc_cache_delete(apc_user_cache, Z_STR_P(hentry)) != 1) { add_next_index_zval(return_value, hentry); Z_TRY_ADDREF_P(hentry); } } ZEND_HASH_FOREACH_END(); } else if (Z_TYPE_P(keys) == IS_OBJECT) { RETURN_BOOL(apc_iterator_delete(keys) != 0); } else { apc_warning("apc_delete() expects a string, array of strings, or APCIterator instance"); RETURN_FALSE; } } PHP_FUNCTION(apcu_entry) { zend_string *key; zend_fcall_info fci = empty_fcall_info; zend_fcall_info_cache fcc = empty_fcall_info_cache; zend_long ttl = 0L; zend_long now = apc_time(); ZEND_PARSE_PARAMETERS_START(2, 3) Z_PARAM_STR(key) Z_PARAM_FUNC(fci, fcc) Z_PARAM_OPTIONAL Z_PARAM_LONG(ttl) ZEND_PARSE_PARAMETERS_END(); apc_cache_entry(apc_user_cache, key, &fci, &fcc, ttl, now, return_value); } /* }}} */ #ifdef APC_DEBUG /* This function is used to test TTL behavior without having to perform sleeps. */ PHP_FUNCTION(apcu_inc_request_time) { zend_long by = 1; ZEND_PARSE_PARAMETERS_START(0, 1) Z_PARAM_OPTIONAL Z_PARAM_LONG(by) ZEND_PARSE_PARAMETERS_END(); if (!APCG(use_request_time)) { php_error_docref(NULL, E_WARNING, "Trying to increment request time while use_request_time is disabled"); return; } /* Ensure APCG(request_time) is primed */ (void) apc_time(); APCG(request_time) += by; } #endif /* {{{ module definition structure */ zend_module_entry apcu_module_entry = { STANDARD_MODULE_HEADER, PHP_APCU_EXTNAME, ext_functions, PHP_MINIT(apcu), PHP_MSHUTDOWN(apcu), PHP_RINIT(apcu), NULL, PHP_MINFO(apcu), PHP_APCU_VERSION, STANDARD_MODULE_PROPERTIES }; /* }}} */ #ifdef COMPILE_DL_APCU ZEND_GET_MODULE(apcu) #ifdef ZTS ZEND_TSRMLS_CACHE_DEFINE(); #endif #endif /* }}} */ /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim>600: noexpandtab sw=4 ts=4 sts=4 fdm=marker * vim<600: noexpandtab sw=4 ts=4 sts=4 */ apcu-5.1.23/php_apc.h0000664000175000017500000000435314523735540013310 0ustar nikicnikic/* +----------------------------------------------------------------------+ | APC | +----------------------------------------------------------------------+ | Copyright (c) 2006-2011 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP 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.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Authors: Daniel Cowgill | | George Schlossnagle | | Rasmus Lerdorf | +----------------------------------------------------------------------+ This software was contributed to PHP by Community Connect Inc. in 2002 and revised in 2005 by Yahoo! Inc. to add support for PHP 5.1. Future revisions and derivatives of this source code must acknowledge Community Connect Inc. as the original contributor of this module by leaving this note intact in the source code. All other licensing and usage conditions are those of the PHP Group. */ #ifndef PHP_APCU_H #define PHP_APCU_H #include "apc.h" #include "apc_globals.h" #define PHP_APCU_VERSION "5.1.23" #define PHP_APCU_EXTNAME "apcu" PHP_APCU_API zend_bool apc_is_enabled(void); extern zend_module_entry apcu_module_entry; #define apcu_module_ptr &apcu_module_entry #define phpext_apcu_ptr apcu_module_ptr #if defined(ZTS) && defined(COMPILE_DL_APCU) ZEND_TSRMLS_CACHE_EXTERN(); #endif #endif /* PHP_APC_H */ /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: * vim>600: noexpandtab sw=4 ts=4 sts=4 fdm=marker * vim<600: noexpandtab sw=4 ts=4 sts=4 */ apcu-5.1.23/README.md0000664000175000017500000000274514523735540013007 0ustar nikicnikicAPCu ==== APCu is an in-memory key-value store for PHP. Keys are of type string and values can be any PHP variables. APCu only supports userland caching of variables. APCu is APC stripped of opcode caching. See [APCu Backwards Compatibility Module](https://github.com/krakjoe/apcu-bc) which provides a drop in replacement for APC. [![Build Status](https://travis-ci.org/krakjoe/apcu.svg?branch=master)](https://travis-ci.org/krakjoe/apcu) [![Build status](https://ci.appveyor.com/api/projects/status/om63glh4g24gi1p9/branch/master?svg=true)](https://ci.appveyor.com/project/krakjoe/apcu/branch/master) Documentation ============ APCu documentation can be found on [php.net](http://php.net/apcu). Reporting Bugs ============= If you believe you have found a bug in APCu, please open an issue: Include in your report *minimal, executable, reproducing code*. Minimal: reduce your problem to the smallest amount of code possible; This helps with hunting the bug, but also it helps with integration and regression testing once the bug is fixed. Executable: include all the information required to execute the example code, code snippets are not helpful. Reproducing: some bugs don't show themselves on every execution, that's fine, mention that in the report and give an idea of how often you encounter the bug. __It is impossible to help without reproducing code, bugs that are opened without reproducing code will be closed.__ Please include version and operating system information in your report. apcu-5.1.23/TECHNOTES.txt0000664000175000017500000003616214523735540013625 0ustar nikicnikicAPCu Quick-Start Braindump This is a rapidly written braindump of how APCu currently works in the form of a quick-start guide to start hacking on APCu. 1. Install and use APC a bit so you know what it does from the end-user's perspective. user-space functions are all explained here: https://www.php.net/apcu 2. Grab the current APC code from https://github.com/krakjoe/apcu apcu/php_apc.c has most of the code for the user-visible stuff. It is also a regular PHP extension in the sense that there are MINIT, MINFO, MSHUTDOWN, RSHUTDOWN, etc. functions. 3. Build it. cd apcu phpize ./configure --enable-apcu make make test cp modules/apcu.so /usr/local/lib/php apachectl restart 4. Debugging Hints apachectl stop gdb /usr/bin/httpd break ?? run -X Grab the .gdbinit from the PHP source tree and have a look at the macros. 5. The basics of APCu APCu has three main component parts: 1) shared memory allocator 2) pooling 3) user land cache 5.1) APCu SMA It is a pretty standard memory allocator, now supporting third party extensions. apc_sma_malloc and apc_sma_free behave to the caller just like malloc and free, they are generated from macros in apc_sma.h Note: apc_sma.h is formatted and designed such that the SMA APCu uses can be used by third parties in their own extensions without interfering with, or consuming the resources of APCu itself apc_sma is a structure of type apc_sma_t, it is statically allocated at runtime, appropriate handlers are generated and set, and the structure made ready for initialization. MINIT then initializes apc_sma with apc_sma_api_init(). APCu SMA then takes care of mmaping the shared memory. ( which you can obtain in any compilation unit with apc_sma_api_extern(apc_sma) ) At this point, we have a completely useless 32MB chunk of memory at our disposal, before it can be used, an apc_cache_header_t is initialized at the beginning of the region of mmapp'ed memory. The header serves as a place to store, among other things, statistical information and a lock. Immediately after the header comes a zero sized block, immediately after that a single block with a size equal to the remaining size of the shared memory. At this point, the shared memory looks like this: +--------+--------+----------------------------------+ | header | 0-size | shared | +--------+--------+----------------------------------+ The blocks are just a simple offset-based linked list (so no pointers): typedef struct block_t block_t; struct block_t { size_t size; /* size of this block */ size_t prev_size; /* size of sequentially previous block, 0 if prev is allocated */ size_t fnext; /* offset in segment of next free block */ size_t fprev; /* offset in segment of prev free block */ #ifdef APC_SMA_CANARIES size_t canary; /* canary to check for memory overwrites */ #endif }; The BLOCKAT macro turns an offset into an actual address for you: #define BLOCKAT(offset) ((block_t*)((char *)shmaddr + offset)) where shmaddr = sma->shaddrs[0] And the OFFSET macro goes the other way: #define OFFSET(block) ((int)(((char*)block) - (char*)shmaddr)) Allocating a block (`sma_allocate`) walks through the linked list of blocks until it finds one that is >= to the requested size. The first call to allocate will hit the second block. We then chop up that block so it looks like this: +--------+-------+-------+-------------------------+ | header | block | block | block | +--------+-------+-------+-------------------------+ Then we unlink that block from the linked list so it won't show up as an available block on the next allocate. So we actually have: +--------+-------+ +-------------------------+ | header | block |------>| block | +--------+-------+ +-------------------------+ And header->avail along with block->size of the remaining large block are updated accordingly. The arrow there representing the link which now points to a block with an offset further along in the segment. When the block is freed the steps are basically just reversed. The block is put back and then the deallocate code looks at the block before and after to see if the block immediately before and after are free and if so the blocks are combined. So you never have 2 free blocks next to each other, apart from at the front with that 0-sized dummy block. This mostly prevents fragmentation. Block start pointers are aligned to the system's word boundary (usually 8 bytes) with the `ALIGNWORD` macro. 5.2) APCu Cache The caching functionality of APCu is provided by a modified version of the APC source code Some simple tweaks have been applied: Locking is written to use the best kind of locking available, and emulate it where it is not to simplify logic. Extension of the SMA to support multiple instances, such that additional caches using APCu do not increase contention of the main APCu cache. The possibility to control more finely what happens when resources become low for APCu. An exposed, coherent, and documented API and example included in the distribution. There's probably some of my blood in it, if you look real close ... The remainder of the document goes on to explain in some detail the cache itself, functionally unchanged by APCu 6. Next up is apc_cache.c which implements the cache logic. Having initialized a suitable allocator, MINIT must call apc_cache_create, using the allocator provided APCu will create a cache. The parameters to apc_cache_create for APCu are defined by various INI settings. API users can provide the same options from anywhere ( their globals for example ). The cache is stored in/described by this struct allocated locally: /* {{{ struct definition: apc_cache_t */ typedef struct _apc_cache_t { void* shmaddr; /* process (local) address of shared cache */ apc_cache_header_t* header; /* cache header (stored in SHM) */ apc_cache_entry_t** slots; /* array of cache slots (stored in SHM) */ apc_sma_t* sma; /* shared memory allocator */ apc_serializer_t* serializer; /* serializer */ size_t nslots; /* number of slots in cache */ zend_long gc_ttl; /* maximum time on GC list for a entry */ zend_long ttl; /* if slot is needed and entry's access time is older than this ttl, remove it */ zend_long smart; /* smart parameter for gc */ zend_bool defend; /* defense parameter for runtime */ } apc_cache_t; /* }}} */ Whenever you see functions that take a 'cache' argument, this is what they take. At the beginning of the cache we have a header. The header looks like this: /* {{{ struct definition: apc_cache_header_t Any values that must be shared among processes should go in here. */ typedef struct _apc_cache_header_t { apc_lock_t lock; /* header lock */ zend_long nhits; /* hit count */ zend_long nmisses; /* miss count */ zend_long ninserts; /* insert count */ zend_long nexpunges; /* expunge count */ zend_long nentries; /* entry count */ zend_long mem_size; /* used */ time_t stime; /* start time */ unsigned short state; /* cache state */ apc_cache_slam_key_t lastkey; /* last key inserted (not necessarily without error) */ apc_cache_entry_t *gc; /* gc list */ } apc_cache_header_t; /* }}} */ Since this is at the start of the shared memory segment, these values are accessible across all processes / threads and hence access to them has to be locked. After the header we have an array of slots. The number of slots is user-defined through the apc.entries_hint ini hint. Each slot is described by: /* {{{ struct definition: apc_cache_slot_t */ typedef struct apc_cache_slot_t apc_cache_slot_t; struct apc_cache_slot_t { apc_cache_key_t key; /* slot key */ apc_cache_entry_t* value; /* slot value */ apc_cache_slot_t* next; /* next slot in linked list */ zend_ulong nhits; /* number of hits to this slot */ time_t ctime; /* time slot was initialized */ time_t dtime; /* time slot was removed from cache */ time_t atime; /* time slot was last accessed */ }; /* }}} */ The apc_cache_slot_t *next there is a linked list to other slots that happened to hash to the same array position. apc_cache_store_internal() shows what happens on a new cache insert. /* calculate hash and entry */ apc_cache_hash_slot(cache, key, &h, &s); entry = &cache->slots[s]; cache->slots is our array of slots in the segment. So, on an insert we find the array position in the slots array by hashing the key provided. If there are currently no other slots there, we just stick the created `apc_cache_entry_t` into the array. while (*entry) { /* process expired entries and check for entry with matching key */ } /* link in new entry */ new_entry->next = *entry; *entry = new_entry; If there are other slots already at this position we walk the link list to get to the end. While walking the linked list we also check to see if the cache has a TTL defined. If while walking the linked list we see a slot that has expired, we remove it since we are right there looking at it. This is the only place we remove stale entries unless the shared memory segment fills up and we force a full expunge via apc_cache_expunge(). apc_cache_expunge() walks all slots attempting deletion, how deletion occurs depends on runtime parameters, see INSTALL for runtime parameter configuration details. apc_cache_find() simply hashes and returns the entry if it is there. If it is there but older than the mtime in the entry we are looking for, we delete the one that is there and return indicating we didn't find it. API users are advised to use apc_cache_fetch over find for simplicity, this ensures correct operation, fetch sets up the call to find and takes care of copying and releasing the entry from the cache to a zval* provided. Next we need to understand what an actual cache entry looks like. Have a look at apc_cache.h for the structs. Here is the definition of apc_cache_key_t: /* {{{ struct definition: apc_cache_key_t */ typedef struct _apc_cache_key_t { const char *str; /* pointer to constant string key */ zend_uint len; /* length of data at str */ zend_ulong h; /* pre-computed hash of key */ time_t mtime; /* the mtime of this cached entry */ apc_cache_owner_t owner; /* the context that created this key */ } apc_cache_key_t; /* }}} */ To create a apc_cache_key_t structure, call apc_cache_make_key(), see apc_cache.h Ok, on to the actual cache entry, here is the definition of apc_cache_entry_t: /* {{{ struct definition: apc_cache_entry_t */ typedef struct apc_cache_entry_t apc_cache_entry_t; struct apc_cache_entry_t { zend_string *key; /* entry key */ zval val; /* the zval copied at store time */ apc_cache_entry_t *next; /* next entry in linked list */ zend_long ttl; /* the ttl on this specific entry */ zend_long ref_count; /* the reference count of this entry */ zend_long nhits; /* number of hits to this entry */ time_t ctime; /* time entry was initialized */ time_t mtime; /* the mtime of this cached entry */ time_t dtime; /* time entry was removed from cache */ time_t atime; /* time entry was last accessed */ zend_long mem_size; /* memory used */ }; /* }}} */ To create an apc_cache_entry_t, call apc_cache_make_entry(), see apc_cache.h Any of the structures taken by apc_cache_* functions have their equivalent apc_cache_make_* If an insertion of an entry should fail, it falls to the caller of insert to free the pooled resources used to create the entry. 7. Serializers The way data is serialized and unserialized can be found in apc_persist.c. Saving to shared memory (persist) is done using `apc_persist_context_t`. Both the entry key and the entry's zval get persisted into shared memory in a continuous block for the single entry. typedef struct _apc_persist_context_t { /* Serializer to use */ apc_serializer_t *serializer; /* Computed size of the needed SMA allocation */ size_t size; /* Whether or not we may have to memoize refcounted addresses */ zend_bool memoization_needed; /* Whether to serialize the top-level value */ zend_bool use_serialization; /* Serialized object/array string, in case there can only be one */ unsigned char *serialized_str; size_t serialized_str_len; /* Whole SMA allocation */ char *alloc; /* Current position in allocation */ char *alloc_cur; /* HashTable storing refcounteds for which the size has already been counted. */ HashTable already_counted; /* HashTable storing already allocated refcounteds. Pointers to refcounteds are stored. */ HashTable already_allocated; } apc_persist_context_t; The ini setting `apc.serializer` can be used to customize the `apc_serializer_t *serializer`. This affects which serializer is used for PHP objects or arrays. (for a top level null/bool/int/float/string, serializers are unnecessary and not used) - `apc.serializer=php` (default) will use serialize() and unserialize() for serializing arrays/ This has lower memory usage than `apc.serializer=default` for most use cases - `apc.serializer=default` is used for arrays that don't contain objects, and will store the array structure in shared memory in a form that allows deduplicating values as well as faster unserialization of small arrays, at the cost of generally having higher memory usage. For arrays that contain objects, it falls back to php's native serialize()/unserialize() - APCu can be configured to use third party serializers if they are compiled with support for apcu. For example, `apc.serializer=igbinary` (https://github.com/igbinary/igbinary) can be used for generally faster unserialization and lower memory usage than apc.serializer=php (requires that igbinary be configured and compiled after APCu is installed) If you made it to the end of this, you should have a pretty good idea of where things are in the code. There is much more reading to do in headers ... good luck ...