# call_back

Definition: | atom a = call_back(integer rid) -- or -- atom a = call_back({'+',integer rid})
Description: | Get a machine address for the Phix routine with the routine_id rid.
pwa/p2js: | Not supported. Note however that Icallback() as defined in pGUI.js is in fact a dummy function that returns its (single/first) parameter unaltered, and that may (or may not) be equally effective in other similar "hand-crafted-replacements-for-dll/so".
Comments: | The resulting address can be used by Windows, or an external C routine in a Windows .dll or Linux shared library (.so), as a "call-back" address for calling your Phix routine. The second form, {'+',rid}, can/should be used on Windows if the routine will be called using the CDECL calling convention, instead of STDCALL. It has no effect when used on Linux, since that is always CDECL anyway. You can set up as many call-back functions as you like. When your routine is called, the argument values will all be machine-sized unsigned (positive) values. You should declare each parameter of your routine as atom, unless you want to impose tighter checking. Your routine must return a machine-sized integer value. Note that sign effects can come into play. The value -1 can, especially if it has been on a fairly colourful journey, arrive (on 32-bit) as #FFFFFFFF aka 4,294,967,295 and that will typecheck if you try and store it in an integer. Or it could occur the other way around completely, with some MAXUINT value in fact turning up as a -1. Code within the callback should be robust and, if at all possible, automatically map such (parameter) values. Theoretically call-backs are not thread safe, see technicalia for details. NOTE: Unfortunately callbacks defined in C with float or double parameters are not supported. The problem is that (eg) atom ptr of rid is effectively used to specify a full machine-word-sized pointer (as in 32/64 bit integer), and consequently that cannot be used to mean "it is a 32bit float or in an xmm register". Maybe this routine could be extended with an optional parameter to more precisely specify such handling, if ever really needed, however I am certainly not suggesting that is likely to be in any way trivial. Thankfully such routines are few and far between, and there is no such problem invoking similar directly via define_c_func(), since going that way we can specify C_FLOAT, C_DOUBLE, etc.
Example: | demo\rosetta\Count_examples.exw
Implementation: | See builtins\VM\pcfunc.e (an autoinclude) for details of the actual implementation.
See Also: | routine_id, Calling C Functions, Icallback
Technicalia | There is a theoretical thread-safety issue with hll call_backs, although #ilASM may offer a workable alternative. The Phix create_thread() function (see builtins\VM\pThreadN.e) is responsible for creating the virtual stack (see builtins\VM\pStack.e) in which the Phix hll code of that thread will run. Should the c_func() code invoke CreateThread() or sys_fork() or whatever, there will be no virtual stack in which to run the Phix hll code. One example I read of is socket.connect(callback), which the article pointed out was asynchronous. In such cases you may have to resort to using a low-level #ilASM{} label/code rather than a hll call_back(), and obviously avoid attempting to make any hll calls, even indirectly, from that low-level callback code. I suppose it might be possible to create a special stack/context for the call-back if pSetSaveEBP/pGetTCB in pHeap.e fail, as per pGetPool, or perhaps just pGetPool/pFreePool at the start of cbhandler, but I cannot think of any way to release the orphans that would create. It might even be possible for the call back handler to create and destroy a virtual stack every time it is called, but that seems rather excessive. Also, either solution would almost certainly make some error reports much shorter in a less than helpful way (ie no call stack). As far as I know, there are no genuinely asynchronous call_backs in OS-level calls, such as Windows API and Linux syscalls, for instance the Windows API ReadFile in OVERLAPPED mode expects you to call GetOverlappedResult at your convenience, rather than rudely interrupt you, and it is probably done that way for somewhat similar reasons.