# How to embed PHP5 into multi-threaded C app?

- Thread: https://externals.io/message/15228
- Original archive: https://news-web.php.net/php.internals/15228
- Started by Bob Beaty on 2005-02-28T13:37:11+00:00
- Messages: 14
- Reply by email to internals@lists.php.net
- More for agents: search with https://externals.io/search.md?q={query} · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

---

## #15228 — Bob Beaty — 2005-02-28T13:37:11+00:00

URL: https://externals.io/message/15228#15228

All,
  I've searched the web for this answer and I'm stumped. I can't find 
the answers. So I thought I'd try the lists. Here goes:
  I have seen how to embed PHP 5 using the code like:

	...
	php_embed_module.ub_write = my_ub_write_func;
	php_embed_module.log_message = my_log_func;
	php_embed_module.sapi_error = my_error_log;
	...
	zend_eval_string(...);
	...

And from this, I looked in the code to see that php_embed_module is a 
static variable that's used in the initialization methods so it *seems* 
as though this can't possibly be thread-safe.
  Yet web servers do it all the time.
  I read on the web that the global variables for the PHP engine are 
maintained in the thread where they were originally defined. This leads 
me to believe that there's the possibility that the php_embed_module 
and other important variables might be thread-local storage, and 
therefore thread-safe.
  Yet if that were the case, how does one define different write, log, 
and error functions so that the engine of one thread does not interfere 
with another?

  In general, my problem is this:
  I have a multi-threaded C++ app that I want to embed the PHP 5 engine 
into. I have read up how to create extensions to PHP, and will do that 
as necessary, but I need to be able to call this engine from my code 
and capture stdout, stderr, etc.
  Can I do this with PHP 5.0.3 as it exists now?
  Are there special things I need to watch out for?
  Any pointers, FAQ sites, etc. that I can look at would be most helpful.
-- 

	Thanks,
		Bob (drbob@TheManFromSPUD.com)
	The Man from S.P.U.D.
	We will write no code before it's designed.

---

## #15229 — Alan Knowles — 2005-02-28T15:21:59+00:00

URL: https://externals.io/message/15228#15229 · In reply to: #15228

these still need tidying up alot, but the do work.
http://docs.akbkhome.com/php_embed.c.txt
http://docs.akbkhome.com/php_embed.h.txt
replace the code in php_embed with them, make sure you compile with the 
zts enabled, and the macros's are similar to the original embed (use 
threaded start call at application start up, and thread start /start end 
within the pthread_start(...callback..) method

check out php.pecl on #efnet you might get lucky..
Regards
Alan


Bob Beaty wrote:

> All,
>  I've searched the web for this answer and I'm stumped. I can't find 
> the answers. So I thought I'd try the lists. Here goes:
>  I have seen how to embed PHP 5 using the code like:
>
>     ...
>     php_embed_module.ub_write = my_ub_write_func;
>     php_embed_module.log_message = my_log_func;
>     php_embed_module.sapi_error = my_error_log;
>     ...
>     zend_eval_string(...);
>     ...
>
> And from this, I looked in the code to see that php_embed_module is a 
> static variable that's used in the initialization methods so it 
> *seems* as though this can't possibly be thread-safe.
>  Yet web servers do it all the time.
>  I read on the web that the global variables for the PHP engine are 
> maintained in the thread where they were originally defined. This 
> leads me to believe that there's the possibility that the 
> php_embed_module and other important variables might be thread-local 
> storage, and therefore thread-safe.
>  Yet if that were the case, how does one define different write, log, 
> and error functions so that the engine of one thread does not 
> interfere with another?
>
>  In general, my problem is this:
>  I have a multi-threaded C++ app that I want to embed the PHP 5 engine 
> into. I have read up how to create extensions to PHP, and will do that 
> as necessary, but I need to be able to call this engine from my code 
> and capture stdout, stderr, etc.
>  Can I do this with PHP 5.0.3 as it exists now?
>  Are there special things I need to watch out for?
>  Any pointers, FAQ sites, etc. that I can look at would be most helpful.

---

## #15230 — Vadka — 2005-02-28T19:08:45+00:00

URL: https://externals.io/message/15228#15230 · In reply to: #15229

> these still need tidying up alot, but the do work.
> http://docs.akbkhome.com/php_embed.c.txt
> http://docs.akbkhome.com/php_embed.h.txt
> replace the code in php_embed with them, make sure you compile with the zts 
> enabled, and the macros's are similar to the original embed (use threaded 
> start call at application start up, and thread start /start end within the 
> pthread_start(...callback..) method
Thread safeness is not a problem for a single thread.
The problem is to call user functions from different threads
(tsrm_ls pointed to somewhere in different threads, global 
vars etc are not protected).

---

## #15232 — Bob Beaty — 2005-02-28T20:24:05+00:00

URL: https://externals.io/message/15228#15232 · In reply to: #15230

Which is my concern.

I've looked at the code differences, and it appears that this 
modification works for running different source files through the 
engine, but I'm concerned about the safety of zend_eval_string() if I 
initialize the engine in one thread and then try to have several 
threads calling zend_eval_string() on different strings.

I'm not convinced that simply making the php_embed_module thread-local 
is going to work either. I'm concerned that the engine was written with 
the idea that only one thread can be initializing the php_embed_module 
and making calls to zend_eval_string(). If this is the case, then I'd 
have to re-write a lot more than php_embed.c to get thread-safety out 
of the engine.

Or am I on the wrong track?

		Bob




>
> 
>
> > […]
> Thread safeness is not a problem for a single thread.
> The problem is to call user functions from different threads
> (tsrm_ls pointed to somewhere in different threads, global vars etc 
> are not protected).
	Thanks,
		Bob (drbob@TheManFromSPUD.com)
	The Man from S.P.U.D.
	We will write no code before it's designed.

---

## #15237 — Alan Knowles — 2005-03-01T03:11:00+00:00

URL: https://externals.io/message/15228#15237 · In reply to: #15232

I think derick does something like this in SRM,
but basically if you want to load something in the global thread,  and 
let the children inherit the data / classes /function etc.
AFAIR you need to serialize the opcodes, and copy them for each thread. 
(or use something like bcompiler to load cached opcodes for you..)

Basically the engine does thread saftey by having a seperate data store 
for each thread. As far as the engine goes, it treats each thread pretty 
much as a seperate process.. 
There was some code in the threads extension to pass variables between 
threads.., cant remember the status of it though.

The code I posted works pretty well, but I include a file as soon as the 
new thread starts up, and dont have any thread global data at present.

Regards
Alan


Bob Beaty wrote:

> Which is my concern.
>
> I've looked at the code differences, and it appears that this 
> modification works for running different source files through the 
> engine, but I'm concerned about the safety of zend_eval_string() if I 
> initialize the engine in one thread and then try to have several 
> threads calling zend_eval_string() on different strings.
>
> I'm not convinced that simply making the php_embed_module thread-local 
> is going to work either. I'm concerned that the engine was written 
> with the idea that only one thread can be initializing the 
> php_embed_module and making calls to zend_eval_string(). If this is 
> the case, then I'd have to re-write a lot more than php_embed.c to get 
> thread-safety out of the engine.
>
> Or am I on the wrong track?
>
>         Bob
>
>
> 
>
> > […]
>
>     Thanks,
>         Bob (drbob@TheManFromSPUD.com)
>     The Man from S.P.U.D.
>     We will write no code before it's designed.

---

## #15238 — Wez Furlong — 2005-03-01T05:56:46+00:00

URL: https://externals.io/message/15228#15238 · In reply to: #15232

ZTS enabled PHP has "strong thread affinity".
Calls into the engine are thread-safe provided that you have
previously initialized the engine on that thread.

Note that you should not efree() memory allocated on one thread from
outside of that thread, on pain of segfault.  eg: resources from one
thread cannot be safely passed on to another thread.

--Wez.




> Which is my concern.
> 
> I've looked at the code differences, and it appears that this
> modification works for running different source files through the
> engine, but I'm concerned about the safety of zend_eval_string() if I
> initialize the engine in one thread and then try to have several
> threads calling zend_eval_string() on different strings.
> 
> I'm not convinced that simply making the php_embed_module thread-local
> is going to work either. I'm concerned that the engine was written with
> the idea that only one thread can be initializing the php_embed_module
> and making calls to zend_eval_string(). If this is the case, then I'd
> have to re-write a lot more than php_embed.c to get thread-safety out
> of the engine.
> 
> Or am I on the wrong track?
> 
>                 Bob
> 
> 
> 
> 
> > […]
>         Thanks,
>                 Bob (drbob@TheManFromSPUD.com)
>         The Man from S.P.U.D.
>         We will write no code before it's designed.

---

## #15240 — Bob Beaty — 2005-03-01T10:35:43+00:00

URL: https://externals.io/message/15228#15240 · In reply to: #15238

Wez,
   OK, I'm with you on this so far, but how do you differentiate 
ub_write, log_message, and sapi_error on different threads? It would 
seem to me that you'd need to have different functions for each thread 
as the calls to ub_write don't include some indication of the thread 
that this is being called under.
   Then again, maybe it's in the php_embed_module if it's tightly bound 
to the thread... For example, if I set the title in the thread-bound 
php_embed_module to something specific for each thread then check that 
within the call to ub_write() I can see who this 'write' belongs to.
   If I'm missing the boat on these function callbacks, or there's an 
easier way to capture stdout, stderr, etc. in a ZTS-enabled PHP/Zend 
environment, please let me know.
   I'm sorry if I seem a bit dense, but I'm trying to figure things out 
and design the code before I start writing it.

		Bob



> ZTS enabled PHP has "strong thread affinity".
> Calls into the engine are thread-safe provided that you have
> previously initialized the engine on that thread.
>
> Note that you should not efree() memory allocated on one thread from
> outside of that thread, on pain of segfault.  eg: resources from one
> thread cannot be safely passed on to another thread.
>
> --Wez.
>
>
>
> On Mon, 28 Feb 2005 14:24:05 -0600, Bob Beaty <drbobbeaty@gmail.com> 
> wrote:
> > […]
>
>

	Thanks,
		Bob (drbob@TheManFromSPUD.com)
	The Man from S.P.U.D.
	We will write no code before it's designed.

---

## #15241 — Wez Furlong — 2005-03-01T14:52:28+00:00

URL: https://externals.io/message/15228#15241 · In reply to: #15240

The TSRMLS_DC magic parameter passes around the thread-local storage
pointer for the thread;   the SG() macro uses that information to get
at the sapi_globals struct for your thread.

You can also stuff your own SAPI related information into
SG(server_context), if you are writing a SAPI:

... in my thread init code ...
struct my_globals *g = calloc(1, sizeof(*g));
SG(server_context) = g;


... in the ub write callback ...
struct my_globals *g = (struct my_globals*)SG(server_context);

If TSRMLS_DC is not present in the function declaration, you can use
TSRMLS_FETCH() to summon it out of thread-local-storage.

--Wez.


> Wez,
>    OK, I'm with you on this so far, but how do you differentiate
> ub_write, log_message, and sapi_error on different threads? It would
> seem to me that you'd need to have different functions for each thread
> as the calls to ub_write don't include some indication of the thread
> that this is being called under.
>    Then again, maybe it's in the php_embed_module if it's tightly bound
> to the thread... For example, if I set the title in the thread-bound
> php_embed_module to something specific for each thread then check that
> within the call to ub_write() I can see who this 'write' belongs to.
>    If I'm missing the boat on these function callbacks, or there's an
> easier way to capture stdout, stderr, etc. in a ZTS-enabled PHP/Zend
> environment, please let me know.
>    I'm sorry if I seem a bit dense, but I'm trying to figure things out
> and design the code before I start writing it.
> 
>                 Bob
> 
> 
> 
> > […]
> 
>         Thanks,
>                 Bob (drbob@TheManFromSPUD.com)
>         The Man from S.P.U.D.
>         We will write no code before it's designed.

---

## #15242 — Vadka — 2005-03-01T17:54:20+00:00

URL: https://externals.io/message/15228#15242 · In reply to: #15237

> I think derick does something like this in SRM,
> but basically if you want to load something in the global thread,  and let 
> the children inherit the data / classes /function etc.
> AFAIR you need to serialize the opcodes, and copy them for each thread. (or 
> use something like bcompiler to load cached opcodes for you..)
For me, inter-threads variables api is working (separated table, holding 
references between threads; must be synched by mutexes).
it will take some time to make that available...

---

## #15243 — Vadka — 2005-03-01T17:57:50+00:00

URL: https://externals.io/message/15228#15243 · In reply to: #15238

> ZTS enabled PHP has "strong thread affinity".
> Calls into the engine are thread-safe provided that you have
> previously initialized the engine on that thread.
Hm...
The problem is when we create a thread and call_user_function for the 
function from the parent thread.

---

## #15244 — Vadka — 2005-03-02T18:08:32+00:00

URL: https://externals.io/message/15228#15244 · In reply to: #15232

> Which is my concern.
>
> I've looked at the code differences, and it appears that this modification 
> works for running different source files through the engine, but I'm 
> concerned about the safety of zend_eval_string() if I initialize the engine 
> in one thread and then try to have several threads calling zend_eval_string() 
> on different strings.
It will not work, as I can see.
It works fine, when I do some preparations, like:

thr=pthread_self();
tsrml=ts_resource_ex(0, &thr);
php_request_startup(tsrml);
zend_eval_string("

But, I must note, that there are no waits for the "thread to start
current thread" in the parent thread in my situation.
Maybe, the code above is not correct (I'm new to PHP's internals), but it 
works correctly.

> I'm not convinced that simply making the php_embed_module thread-local is 
> going to work either. I'm concerned that the engine was written with the idea 
> that only one thread can be initializing the php_embed_module and making 
> calls to zend_eval_string(). If this is the case, then I'd have to re-write a 
> lot more than php_embed.c to get thread-safety out of the engine.
> Or am I on the wrong track?
Imagine, we have (usually) situation, when we are running a function in a 
separate thread (such idea is partially realized in pecl/threads).
So, if there are several threads working with one parsed script, we need 
to provide a kind of task context for each thread +  mechanics for 
sync/async methods.
...maybe, I'm on the wrong track.... :)

---

## #15245 — D.Walsh — 2005-03-02T20:29:15+00:00

URL: https://externals.io/message/15228#15245 · In reply to: #15244

How do I select an appropriate LOGO_GUID?

-- Dale

---

## #15346 — D.Walsh — 2005-03-10T14:13:11+00:00

URL: https://externals.io/message/15228#15346

> D.Walsh wrote:
> > […]
>
> A GUID/UUID is always a safe bet, on linux you can use
> the uuidgen tool to create such a unique identifier,
> other systems should provide similar tools.
>
> Example:
>
> $ uuidgen
> afa5e8bc-a6e4-4305-9a62-872bf1b4b450
>
> (you can also use the uuid extension from PECL)
>
> PS: please don't start a new thread by replying to
>     an existing message. Your message was deeply
>     nested into the
>     "How to embed PHP5 into multi-threaded C app?"
>     thread and anyone not interested in that topic
>     has most likely missed your question.
>
> -- 
> Hartmut Holzgraefe  <hartmut@php.net>

Basically what your saying is that it is a unique ID of randomly 
generated hex values based on an algorithm with no significance other 
than being unique, made unique over both space and time by combining a 
value unique to the computer on which it was generated, usually the 
Ethernet hardware address and a value representing the number of 
100-nanosecond intervals since October 15, 1582 at 00:00:00.

I was expecting the value to have some kind of meaning or divine 
purpose, not something so random in meaning and generation.

I'll use a generated value from uuidgen  with "PHP" prepended for the 
sake of semantics.

Thanks for the response and enlightenment.

Is there also a utility to generate the the logo in the required text 
syntax or should I just create a quick hack to get the job done?

-- Dale

---

## #15349 — Johannes Schlueter — 2005-03-10T14:25:11+00:00

URL: https://externals.io/message/15228#15349 · In reply to: #15346

Hi Dale,

D . Walsh wrote:
> Is there also a utility to generate the the logo in the required text
> syntax or should I just create a quick hack to get the job done?

as I wrote in a posting some weeks ago: PECL_Gen has Logo-Support. Even if
you won't use PECL_Gen for your extension you could check and use it's
code.

johannes
-- 
Johannes Schlüter                           Mayflower GmbH / ThinkPHP
http://thinkphp.de                            http://blog.thinkphp.de
