Hi,

I noticed that the JIT stack handling cause a lot of misunderstanding. It was 
my fault, I thought the "CONTROLLING THE JIT STACK" part of pcrejit.3 man page 
was enough. I realized the concept (reasons) of the JIT stack are missing.

Probably the best way to explain this is through questions:

1) Why do we need the JIT stack?
PCRE (and JIT) is a recursive, depth-first engine, so it needs a stack where 
the local data of the current node is pushed before checking its child nodes. 
Allocating real machine stack on some platforms are difficult. For example, the 
stack chain needs to be updated every time if we extend the stack on PowerPC. 
Although it is possible, its updating time overhead decreases performance. So 
we do the recursion in memory.

2) Why don't we simply allocate a block of memory with malloc?
Modern OS-es has a nice feature: they can reserve an address space instead of 
allocating memory. We can safely allocate memory pages inside this address 
sapce, so the stack could grow without moving memory data (this is important 
because of pointers). Thus we can allocate 1M address space, and use only a 
single memory page (usually 4K) if that is enough. However, we can still grow 
up to 1M anytime if needed.

3) Who "owns" the stack?
The owner of the stack is the user program, not the jit studied pattern or 
anything else. The user program must ensure:
 - If a stack is used by pcre_exec (since it is assigned to the pattern 
currently runing), that stack must not be used by any other threads (to avoid 
overwriting the same memory area). The best practice for multithreaded programs 
to allocate a stack for each thread, and return this stack through the JIT 
callback function.
 - You can free the stack anytime, as long as it will not be used by pcre_exec 
anymore. When you assign the stack to a pattern, only a pointer is set. There 
is no refcounting or any other magic. You can free the patterns and stacks in 
any order, anytime. Just DO NOT call a pcre_exec with a pattern pointing to an 
already freed stack, that will cause SEGFAULT. (And do not free a stack 
currently used by a pcre_exec in another thread). The solution for 
multithreaded programs are above. You can also replace the stack for the 
patterns as well anytime. You can even free the previous stack before 
replacing. The only rule is the rule for pcre_exec above.

4) Shall I allocate/free a stack every time before/after a pcre_exec?
No. Too costly. But you could implement some clever idea which release the 
stack if it is not used in lets say 2 minutes. Or anything else. The JIT 
callback can help to achive this without keepnig a list of the currently jit 
studied patterns.

5) Ok the stack is for long term memory allocation. But what happens if a 
pattern cause stack overflow with the stack of 1M? Is that 1M kept until the 
stack free? Especially on embedded sytems, it might be a good idea to release 
memory sometimes without freeing the stack.
There is no API for this at the moment. Probably a function call which returns 
with the currently allocated memory for any stack and another which allows 
releasing memory (shrinking the stack) would be a good idea if someone needs 
this.

6) This is too much of a headache. Isn't there any better solution for JIT 
stack handling?
No, thanks to Windows... If pthreads would be used everywhere, we could throw 
out this  complicated API.

I hope this info is useful.

Regards,
Zoltan


-- 
## List details at https://lists.exim.org/mailman/listinfo/pcre-dev 

Reply via email to