a) Yes, that is right. And since any call to a haxe function might alloc something, you need it before making a haxe call too.
When you call from haxe to native, the top-of-stack should already be set, since the calling thread would already have needed set this up.
If you then call back into haxe from this native function, you do not need to re-setup the stack either, since it should still be good from when haxe set it up.
You will need to manually call it if you detach the thread, or if it is a "foreign thread" - ie, allocated by the OS. Typically, these might be from an "on needs new sample" native audio callback, or a touch event on android, or some native timer or an ios async-block. It really depends if you created the thread with "Thread.create" in haxe. (or you are bootstrapping the main class).
b) I guess you must decide if your thread is "normally attached" or "normally detached". Haxe created threads are always "normally attached".
If you are normally attached, you need to enter-blocking if you could potentially block.
If you are normally detached, you would typically attach(AutoHaxe) - make some kind of callback - and then detach. The thread can now safely block, or exit, and do whatever it wants, so no need to call enter-blocking.
The enter/exit blocking calls are mildly expensive. So no need to bother if you are going to do, say 1ms worth of work. The worst that can happen is that all the other haxe threads stall for 1ms while the wait for you to complete. But if you are doing something open-ended - eg, network io may take tens of seconds, you should enter blocking mode. Especially if you are waiting for a mutex that a haxe thread may potentially hold - you could deadlock pretty easily. All the haxe std-io calls have this built-in. So efficiency is the main reason for not going crazy with this call.
set_top_of_stack(top,force)
top = the address of a local variable, which will become the top-of-stack. All local variables and arguments will be pushed "below" this (stacks go "downwards") by the c++ compiler
= 0 means detach thread from hxcpp
force = false. This case has one very specific use - it is for the application main thread that initializes haxe and then may call into haxe from different stack positions internally. By using non-force, hxcpp will move the top-of-stack up, but not down, ensuring all stack locations are covered. It is really for a simple single-threaded app, and best not to use this.
force=true. The meaning of this changed a bit, but force basically means "push/pop mode" (rather than ratchet mode). This keeps track of re-entrant stack calls and adjusts the stack appropriately.
So:
(_,false) -> do not use directly
(&i,true) -> Ensure hxcpp sees stack variables "below" i, and increase thread attach count
(0,true) -> detach one count from hxcpp
Hugh