2. Hello everybody
Julien PAULI
Programming in PHP since early 2000s
PHP Internals hacker and trainer
PHP 5.5/5.6 Release Manager
Working at SensioLabs in Paris - Blackfire
Writing PHP tech articles and books
http://phpinternalsbook.com
@julienpauli - github.com/jpauli - jpauli@php.net
Like working on OSS such as PHP :-)
3. TOC
Recall on computer parallel programming
What are threads ?
Threads VS process
The PHP multi-tasking model
Zend Thread Safe mode
What - why - how ?
Parallel programming with PHP
pcntl
pthread
4. Computer architecture
Nowadays we own machines
With several CPUs
With several-core CPUs
Multitasking
Time division of one CPU frequency
Concurrency
Using several CPUs (or Core) at the same time
Parallelism
Both above solutions mixed
7. OS Process
The lowest level representation of "a task"
The OS scheduler does the job
8. Processes are heavy
Processes are heavy guys
Creating a process means a lot of work for the Kernel
Lots of CPU instructions involved
Many memory movements
A process eats some memory
For its own structures
11. Threads are light process
Threads have been designed like processes
But their goal
is to be lighter
is to be userland programmable
They thus share some data between them
They are lighter to create
Less structure involved
Less memory access / movement on management
13. Threads share memory
Threads leave in processes
If the process dies, all its threads die
Threads share their process'
heap
data
sigmask
FDs
Threads got their own
stack
sigmask
CPU registers
14. Threads dangers
Threads share the heap and the data segment
Thus while programming, threads share the
global state
Accessing the global state with several threads
Needs extra care
Memory barriers
Semaphores and locks
15. Threads VS processes
Threads
Will by default share memory
Will share file descriptors
Will share filesystem context
Will share signal handling
Processes
Will by default not share memory
Most file descriptors not shared
Don't share filesystem context
Don't share signal handling
16. PHP Multitasking
Since 1995 ...
Rely on the webserver to process several requests at
the same time
Rely on FastCGI
users
17. Multitasking PHP
To treat several requests
The webserver embedding PHP forks itself
Apache
The webserver forks itself and pass the web request
to PHP CGI processes
Using FastCGI : PHP forks itself
php-fpm
18. PHP in a threaded env
PHP could leave in a threaded environment
If the webserver uses threads to handle concurrency
Apache with mpm_worker
IIS under Windows
Windows heavily makes use of threads
Unix tend to prefer using processes
20. Zend Thread Safety
PHP will never itself make use threads
PHP's code is NOT threaded
But PHP could, despite him, live in threads
PHP thus needs to be programmed
So that it can access thread shared memory safely
This is called the Zend Thread Safe mode : ZTS
21. ZTS goals
ZTS is a way of programming PHP core and
extensions , in C
A layer that eases access to globals and turn
them thread-safe using one OS supported
thread lib
Let's see how
22. ZTS, abstract thread model
Several thread library exists
They all got their own behavior / API / performances
ZTS provides macros and automation to abstract
that
ZTS supports
GNU Pth
POSIX Thread (pthread)
SGI's State Thread
BeOS Threads
Choose at compile time (--with-tsrm-???)
23. TSRM
TSRM stands for Thread Safe Resource Manager
This is the C code layer behind ZTS mode
TSRM/ in PHP source code
Activate using --enable-maintainer-zts
This will build a ZTS PHP
24. Example program
static int val; /* true global */
PHP_MINIT(wow_ext) /* PHP Module initialization */
{
if (something()) {
val = 3; /* writing to a true global */
}
}
PHP_RINIT(wow_ext) /* PHP Request initialization */
{
if (something()) {
WOW_G(val) = 3; /* writing to a thread global */
}
}
25. TSRM macros
Accessing globals while in a thread must be
done using TSRM macros
#ifndef ZTS
#define WOW_G(v) wow_globals.v
#else
#define WOW_G(v) (((wow_globals *)
(*((void ***) tsrm_get_ls_cache()))[((wow_globals_id)-1)])->v)
#endif
27. Pthread keys
In pthread, each thread is given a key.
That key is used to access a TLS : Thread Local
Storage
A piece of memory owned by each thread
The compiler takes care of the hard job
This is where we'll store our "globals"
28. Extensions compilation
At compilation, each extension declares
a pointer to some TLS space
__thread is used
An id (integer) which will retain this extension
specific storage
BF_DECLARE_ZEND_GLOBALS
ts_rsrc_id blackfire_globals_id; __thread void *_tsrm_ls_cache = ((void *)0);;
31. Allocating resources per thread
This is done at every new request
ts_resource_ex() checks if this thread's got data
If not, it calls for allocate_new_resource()
This will set the thread storage using the current thread key
32. Allocating thread resources
static void allocate_new_resource(tsrm_tls_entry **thread_resources_ptr,
THREAD_T thread_id)
{
int i;
(*thread_resources_ptr) = (tsrm_tls_entry *) malloc(sizeof(tsrm_tls_entry));
(*thread_resources_ptr)->storage = (void **) malloc(sizeof(void *)*id_count);
(*thread_resources_ptr)->count = id_count;
(*thread_resources_ptr)->thread_id = thread_id;
(*thread_resources_ptr)->next = NULL;
/* Set thread local storage to this new thread resources structure */
tsrm_tls_set(*thread_resources_ptr);
(*thread_resources_ptr)->storage[i] = (void *) malloc(resource_types_table[i].size);
if (resource_types_table[i].ctor) {
resource_types_table[i].ctor((*thread_resources_ptr)->storage[i]);
}
tsrm_mutex_unlock(tsmm_mutex);
}
33. Extensions thread startup
For each new thread, extensions should read
the local storage ...
PHP_GINIT_FUNCTION(blackfire)
{
#ifdef ZTS
ZEND_TSRMLS_CACHE_UPDATE();
#endif
/* ... ... */
}
_tsrm_ls_cache = tsrm_get_ls_cache();
_tsrm_ls_cache = pthread_getspecific(tls_key);
34. Accessing resources per thread
For each new thread, extensions should read
the local storage ...
To better read their own memory part after
#define BF_G(v)
(((zend_blackfire_globals *) (*((void ***) _tsrm_ls_cache))[((blackfire_globals_id)-1)])->(v))
Thread Safe Resource Mana
_ Local Storage _ cache
extension storage id
35. ZTS ?
A nice layer, that eases and abstract all the
thread and TLS management
If you use the cache, then it is fully performant
Compile PHP with
-DZEND_ENABLE_STATIC_TSRMLS_CACHE=1
However, it slows down PHP's startup
We don't care
It slows down request creation for every new
thread
That is however clearly acceptable
36. When to use ZTS ?
If you run Windows with Apache
Threads are used , so compile with ZTS
If you run Unix and need ZTS
You use an extension that needs the interpreter to be
built with ZTS
Like the pthread extension
You use some kind of webserver that embed PHP and
makes use of threads
Like Apache with mpm_worker
In a HUGE majorty of cases, you'll use Unix, and
you won't need ZTS
37. Check if ZTS is used
Use the PHP_ZTS constant in PHP
See the output of php -v
See the output of phpinfo()
As a PHP developer, you shouldn't care about ZTS
in your code
As a PHP extension developer, you should be
aware of how it works, and use dedicated macros
38. ZTS ABI
Obviously, ZTS ABI is not compatible with NTS
ABI
Thus extensions must be rebuilt
Check their install dir
39. Using threads in PHP Land
This is possible
You need ext/pthread for that
http://php.net/manual/fr/book.pthreads.php
http://pthreads.org/
This is experimental
You must really be used to thread programming
to use ext/pthread
40. Using threads in PHP Land
Not really a good idea
At least, there exists better languages for that
C , C++ or Java
Those are languages designed to provide thread
usage
PHP is not !
You should not need to parallelize tasks when
using the PHP language
If so, then probably you should use another language
41. Using processes in PHP land
ext/pcntl
I guess you already know it
It shadows Unix processes
Know your machine and your OS
Obviously not available for Windows
fork(), wait(), waitpid(), signal() ...
All those calls are syscalls available using C
Consider using C for true performances and to finely
master what you do
Even if PHP adds a really thin layer on top of that stuf
42. ZTS and threads : concluding
PHP is thread-safe
Compile with --enable-maintainer-zts
You'll activate Zend Thread Safety
You only need ZTS is some uncommon specific
cases
Take care of "exotic" extensions
They may not be thread-safe themselves
Analyze before using them
Please don't blindly blame PHP