-
Notifications
You must be signed in to change notification settings - Fork 7.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
19 changed files
with
662 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
name: Docs | ||
on: | ||
push: | ||
branches: | ||
- master | ||
paths: | ||
- docs/* | ||
pull_request: | ||
paths: | ||
- docs/* | ||
jobs: | ||
pages: | ||
runs-on: ubuntu-22.04 | ||
permissions: | ||
pages: write | ||
id-token: write | ||
steps: | ||
- name: git checkout | ||
uses: actions/checkout@v4 | ||
- name: Install dependencies | ||
run: pip install sphinx-design sphinxawesome-theme rstfmt | ||
- name: Check formatting | ||
run: rstfmt --check -w 100 docs/source | ||
- name: Publish | ||
if: github.event_name == 'push' | ||
uses: sphinx-notes/pages@v3 | ||
with: | ||
checkout: false | ||
documentation_path: docs/source |
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
build/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
# php-src docs | ||
|
||
This is the home of the php-src internal documentation. It is in very early stages, but is intended | ||
to become the primary place where new information about php-src is documented. Over time, it is | ||
expected to replace various mediums like: | ||
|
||
* https://www.phpinternalsbook.com/ | ||
* https://wiki.php.net/internals | ||
* Blogs from contributors | ||
|
||
## How to build | ||
|
||
`python` 3 and `pip` are required. | ||
|
||
```bash | ||
pip install sphinx sphinx-design sphinxawesome-theme | ||
make html | ||
``` | ||
|
||
That's it! You can view the documentation under `./build/html/index.html` in your browser. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
@ECHO OFF | ||
|
||
pushd %~dp0 | ||
|
||
REM Command file for Sphinx documentation | ||
|
||
if "%SPHINXBUILD%" == "" ( | ||
set SPHINXBUILD=sphinx-build | ||
) | ||
set SOURCEDIR=source | ||
set BUILDDIR=build | ||
|
||
%SPHINXBUILD% >NUL 2>NUL | ||
if errorlevel 9009 ( | ||
echo. | ||
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx | ||
echo.installed, then set the SPHINXBUILD environment variable to point | ||
echo.to the full path of the 'sphinx-build' executable. Alternatively you | ||
echo.may add the Sphinx directory to PATH. | ||
echo. | ||
echo.If you don't have Sphinx installed, grab it from | ||
echo.https://www.sphinx-doc.org/ | ||
exit /b 1 | ||
) | ||
|
||
if "%1" == "" goto help | ||
|
||
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% | ||
goto end | ||
|
||
:help | ||
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% | ||
|
||
:end | ||
popd |
Empty file.
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
# Configuration file for the Sphinx documentation builder. | ||
# | ||
# For the full list of built-in configuration values, see the documentation: | ||
# https://www.sphinx-doc.org/en/master/usage/configuration.html | ||
|
||
from dataclasses import asdict | ||
from sphinxawesome_theme import ThemeOptions | ||
from sphinxawesome_theme.postprocess import Icons | ||
from sphinx.highlighting import lexers | ||
from pygments.lexers.web import PhpLexer | ||
|
||
lexers['php'] = PhpLexer(startinline=True) | ||
lexers['php-annotations'] = PhpLexer(startinline=True) | ||
|
||
project = 'php-src docs' | ||
author = 'The PHP Group' | ||
extensions = [ | ||
'sphinx_design', | ||
'sphinxawesome_theme.highlighting', | ||
] | ||
templates_path = ['_templates'] | ||
html_theme = 'sphinxawesome_theme' | ||
html_static_path = ['_static'] | ||
html_title = project | ||
html_permalinks_icon = Icons.permalinks_icon | ||
theme_options = ThemeOptions( | ||
show_prev_next=True, | ||
extra_header_link_icons={ | ||
'repository on GitHub': { | ||
'link': 'https://github.com/php/php-src', | ||
'icon': ( | ||
'<svg height="26px" style="margin-top:-2px;display:inline" ' | ||
'viewBox="0 0 45 44" ' | ||
'fill="currentColor" xmlns="http://www.w3.org/2000/svg">' | ||
'<path fill-rule="evenodd" clip-rule="evenodd" ' | ||
'd="M22.477.927C10.485.927.76 10.65.76 22.647c0 9.596 6.223 17.736 ' | ||
'14.853 20.608 1.087.2 1.483-.47 1.483-1.047 ' | ||
'0-.516-.019-1.881-.03-3.693-6.04 ' | ||
'1.312-7.315-2.912-7.315-2.912-.988-2.51-2.412-3.178-2.412-3.178-1.972-1.346.149-1.32.149-1.32 ' # noqa | ||
'2.18.154 3.327 2.24 3.327 2.24 1.937 3.318 5.084 2.36 6.321 ' | ||
'1.803.197-1.403.759-2.36 ' | ||
'1.379-2.903-4.823-.548-9.894-2.412-9.894-10.734 ' | ||
'0-2.37.847-4.31 2.236-5.828-.224-.55-.969-2.759.214-5.748 0 0 ' | ||
'1.822-.584 5.972 2.226 ' | ||
'1.732-.482 3.59-.722 5.437-.732 1.845.01 3.703.25 5.437.732 ' | ||
'4.147-2.81 5.967-2.226 ' | ||
'5.967-2.226 1.185 2.99.44 5.198.217 5.748 1.392 1.517 2.232 3.457 ' | ||
'2.232 5.828 0 ' | ||
'8.344-5.078 10.18-9.916 10.717.779.67 1.474 1.996 1.474 4.021 0 ' | ||
'2.904-.027 5.247-.027 ' | ||
'5.96 0 .58.392 1.256 1.493 1.044C37.981 40.375 44.2 32.24 44.2 ' | ||
'22.647c0-11.996-9.726-21.72-21.722-21.72" ' | ||
'fill="currentColor"/></svg>' | ||
), | ||
}, | ||
}, | ||
) | ||
html_theme_options = asdict(theme_options) | ||
pygments_style = 'sphinx' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
################# | ||
Data structures | ||
################# | ||
|
||
.. toctree:: | ||
:hidden: | ||
|
||
zval | ||
reference-counting | ||
|
||
This section provides an overview of the core data structures used in php-src. |
228 changes: 228 additions & 0 deletions
228
docs/source/core/data-structures/reference-counting.rst
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,228 @@ | ||
#################### | ||
Reference counting | ||
#################### | ||
|
||
In languages like C, when you need memory for storing data for an indefinite period of time or in a | ||
large amount, you call ``malloc`` and ``free`` to acquire and release blocks of memory of some size. | ||
This sounds simple on the surface but turns out to be quite tricky, mainly because the data may not | ||
be freed for as long as it is used, anywhere in the program. Sometimes, this makes it unclear who is | ||
responsible for freeing the memory, and when to do so. Failure to handle this correctly may result | ||
in use-after-free, double-free, and memory leaks. | ||
|
||
Very rarely do you have to think about memory management when working in PHP. The engine takes care | ||
of this for you by tracking which values are no longer needed. It does this by assigning a reference | ||
count to each value, often abbreviated as refcount or RC. Whenever a reference to a value is passed | ||
to somebody else, its reference count is increased to indicate the value is now used by another | ||
party. When the party no longer needs the value, it is responsible for decreasing the reference | ||
count. Once the reference count reaches zero, we know the value is no longer needed anywhere in the | ||
program, and that it may be freed. | ||
|
||
.. code:: php | ||
$a = new stdClass; // RC 1 | ||
$b = $a; // RC 2 | ||
unset($a); // RC 1 | ||
unset($b); // RC 0, free | ||
Reference counting is needed for types that store auxiliary data, which are the following: | ||
|
||
- Strings | ||
- Arrays | ||
- Objects | ||
- References | ||
- Resources | ||
|
||
These are either reference types (objects, references and resources) or they are large types that | ||
don't fit in a single ``zend_value`` directly (strings, arrays). More simple types either don't | ||
store a value at all (``null``, ``false``, ``true``) or their value is small enough to fit directly | ||
in ``zend_value`` and copied when passed somewhere else (``int``, ``float``). | ||
|
||
All of the reference counted types share a common initial struct sequence. | ||
|
||
.. code:: c | ||
typedef struct _zend_refcounted_h { | ||
uint32_t refcount; /* reference counter 32-bit */ | ||
union { | ||
uint32_t type_info; | ||
} u; | ||
} zend_refcounted_h; | ||
struct _zend_string { | ||
zend_refcounted_h gc; | ||
// ... | ||
}; | ||
struct _zend_array { | ||
zend_refcounted_h gc; | ||
// ... | ||
}; | ||
This explains the ``zval.value.counted`` union member in the ``zval`` struct we saw in the ``zval`` | ||
chapter. It refers to the initial ``gc`` field of any reference counted type, in case we don't care | ||
about which concrete type we're dealing with. | ||
|
||
The ``zend_refcounted_h`` struct is simple. It contains the reference count, and a ``type_info`` | ||
field that repeats some of the type information that is also stored in the ``zval``, for situations | ||
where we're not dealing with a ``zval`` directly. It also stores some additional fields, described | ||
under `GC flags`_. | ||
|
||
******** | ||
Macros | ||
******** | ||
|
||
As with ``zval``, ``zend_refcounted_h`` members should not be accessed directly. Instead, you should | ||
use the provided macros. There are macros that work with reference counted types directly, prefixed | ||
with ``GC_``, or macros that work on ``zval`` values, usually prefixed with ``Z_``. Unfortunately, | ||
naming is not always consistent. | ||
|
||
.. list-table:: ``zval`` macros | ||
:header-rows: 1 | ||
|
||
- - Macro | ||
- Non-RC [#non-rc]_ | ||
- Description | ||
|
||
- - ``Z_REFCOUNT[_P]`` | ||
- No | ||
- Returns the reference count. | ||
|
||
- - ``Z_ADDREF[_P]`` | ||
- No | ||
- Increases the reference count. | ||
|
||
- - ``Z_TRY_ADDREF[_P]`` | ||
- Yes | ||
- Increases the reference count. May be called on any ``zval``. | ||
|
||
- - ``zval_ptr_dtor`` | ||
- Yes | ||
- Decreases the reference count and frees the value if the reference count reaches zero. | ||
|
||
- - ``Z_DELREF[_P]`` | ||
- No | ||
- Decreases the reference count. Note that this will not actually free the value if the | ||
reference count reaches zero. You should usually use ``zval_ptr_dtor`` instead. | ||
|
||
- - ``Z_TRY_DELREF[_P]`` | ||
- Yes | ||
- Decreases the reference count. Note that this will not actually free the value if the | ||
reference count reaches zero. You should usually use ``zval_ptr_dtor`` instead. | ||
|
||
.. [#non-rc] | ||
Whether the macro works with non-reference counted types. If it does, the operation is usually a | ||
no-op. If it does not, using the macro on these values is undefined behavior. | ||
.. list-table:: ``zend_refcounted_h`` macros | ||
:header-rows: 1 | ||
|
||
- - Macro | ||
- Immutable [#immutable]_ | ||
- Description | ||
|
||
- - ``GC_REFCOUNT[_P]`` | ||
- Yes | ||
- Returns the reference count. | ||
|
||
- - ``GC_ADDREF[_P]`` | ||
- No | ||
- Increases the reference count. | ||
|
||
- - ``GC_TRY_ADDREF[_P]`` | ||
- Yes | ||
- Increases the reference count. | ||
|
||
- - ``GC_DTOR[_P]`` | ||
- Yes | ||
- Decreases the reference count and frees the value if the reference count reaches zero. | ||
|
||
- - ``GC_DELREF[_P]`` | ||
- No | ||
- Decreases the reference count. Note that this will not actually free the value if the | ||
reference count reaches zero. You should usually use ``GC_DTOR_[P]`` instead. | ||
|
||
- - ``GC_TRY_DELREF[_P]`` | ||
- Yes | ||
- Decreases the reference count. Note that this will not actually free the value if the | ||
reference count reaches zero. You should usually use ``GC_DTOR_[P]`` instead. | ||
|
||
.. [#immutable] | ||
Whether the macro works with immutable types, described under `Immutable reference counted types`_. | ||
*********************************** | ||
Immutable reference counted types | ||
*********************************** | ||
|
||
Sometimes, even a reference counted type is not reference counted. When PHP runs in a multi-process | ||
or multi-threaded environment with opcache enabled, it shares some common values between processes | ||
or threads to reduce memory consumption. As you may know, sharing memory between processes or | ||
threads can be tricky and requires special care when modifying values. In particular, modification | ||
usually requires exclusive access to the memory so that the other processes or threads wait until | ||
the value is done being updated. In this case, this synchronization is avoided by making the value | ||
immutable and never modifying the reference count. Such values will receive the ``GC_IMMUTABLE`` | ||
flag in their ``gc->u.type_info`` field. | ||
|
||
Some macros like ``GC_TRY_ADDREF`` will guard against immutable values. You should not use immutable | ||
values on some macros, like ``GC_ADDREF``. This will result in undefined behavior, because the macro | ||
will not check whether the value is immutable before performing the reference count modifications. | ||
You may execute PHP with the ``-d opcache.protect_memory=1`` flag to mark the shared memory as | ||
read-only and trigger a hardware exception if the code accidentally attempts to modify it. | ||
|
||
***************** | ||
Cycle collector | ||
***************** | ||
|
||
Sometimes, reference counting is not enough. Consider the following example: | ||
|
||
.. code:: php | ||
$a = new stdClass; | ||
$b = new stdClass; | ||
$a->b = $b; | ||
$b->a = $a; | ||
unset($a); | ||
unset($b); | ||
When this code finishes, the reference count of both ``$a`` and ``$b`` will still be 1, as they | ||
reference each other. This is called a reference cycle. | ||
|
||
PHP implements a cycle collector that detects cycles and frees values that are only reachable | ||
through their own references. The cycle collector will record values that may be involved in a | ||
cycle, and run when this buffer becomes full. It is also possible to invoke it explicitly by calling | ||
the ``gc_collect_cycles()`` function. The cycle collector design is described in the `Cycle | ||
collector <todo>`_ chapter. | ||
|
||
********** | ||
GC flags | ||
********** | ||
|
||
.. code:: c | ||
/* zval_gc_flags(zval.value->gc.u.type_info) (common flags) */ | ||
#define GC_NOT_COLLECTABLE (1<<4) | ||
#define GC_PROTECTED (1<<5) /* used for recursion detection */ | ||
#define GC_IMMUTABLE (1<<6) /* can't be changed in place */ | ||
#define GC_PERSISTENT (1<<7) /* allocated using malloc */ | ||
#define GC_PERSISTENT_LOCAL (1<<8) /* persistent, but thread-local */ | ||
The ``GC_NOT_COLLECTABLE`` flag indicates that the value may not be involved in a reference cycle. | ||
This allows for a fast way to detect values that don't need to be added to the cycle collector | ||
buffer. Only arrays and objects may actually be involved in reference cycles. | ||
|
||
The ``GC_PROTECTED`` flag is used to protect against recursion in various internal functions. For | ||
example, ``var_dump`` recursively prints the contents of values, and marks visited values with the | ||
``GC_PROTECTED`` flag. If the value is recursive, it prevents the same value from being visited | ||
again. | ||
|
||
``GC_IMMUTABLE`` has been discussed in `Immutable reference counted types`_. | ||
|
||
The ``GC_PERSISTENT`` flag indicates that the value was allocated using ``malloc``, instead of PHPs | ||
own allocator. Usually, such values are alive for the entire lifetime of the process, instead of | ||
being freed at the end of the request. See the `Zend allocator <todo>`_ chapter for more | ||
information. | ||
|
||
The ``GC_PERSISTENT_LOCAL`` flag indicates that a ``CG_PERSISTENT`` value is only accessibly in one | ||
thread, and is thus still safe to modify. This flag is only used in debug builds to satisfy an | ||
``assert``. |
Oops, something went wrong.