ECho V2 makes this duality a bit more explicit. Conceptually, the EControlContext somehow identifies a thread which can run handlers and otherwise service the channel. At this point, one can only acquire an EControlContext by using ECho_CM_init() to initialize ECho message handling in a Connection Manager. Future releases will support other forms of EControlContext variables. In the case of CM-derived EControl contexts, the CM initialization allows ECho to piggyback on the Connection Manager and use the thread of control which is used by CM for servicing the network. In particular, there are a couple of common ways to structure the control flow in ECho/CM programs. In the simplest, non-threaded program the control flow looks like this:
int main() { CManager cm; EControlContext ec; /* ... */ cm = CManager_create(); ec = ECho_CM_init(cm); /* ... */ CMrun_network(cm); }In this program, the CMrun_network() call runs the CM network handler using the thread of the main program. Non-threaded programs are often more efficient than threaded programs, but some CM transports cannot run without additional threads to support specialized blocking network features.
For threaded programs, CM relies on the gen_threads package to provide a generic wrapper around threads libraries. After gen_threads has been initialized, the subroutine CMform_comm_thread() causes CM to fork a kernel-level thread to handle network traffic. ECho will also use this thread for various asynchronous tasks. A sample control structure for a threaded program using Pthreads is given below:
int main() { CManager cm; EControlContext ec; int forked; gen_pthread_init(); cm = CManager_create(); forked = CMfork_comm_thread(cm); if (!forked) { printf("Fork of communications thread failed, exitting\n"); exit(1); } ec = ECho_CM_init(cm); /* * communications thread is forked - main() should not return * until time for program exit. */ }There is no need to call the equivalent of DExchange_listen() as there was in ECho V1. The ECho_CM_init() call will ensure that a listen point is created if necessary.
ECho routines which did not have a DExchange parameter should have the same API under ECho V2 as they did before. (Proto Channels are not yet functional, so the ECproto_* functions will not work.)
ECho applications can also be built with libtool. How this is done is best explained by the libtool documentation, available from http://www.gnu.org/software/libtool/libtool.html. If libtool is utilized, using ECho involves adding ``-lecho'' to the link line, preceeded if necessary by an appropriate ``-Llibdirectory'' flag. Libtool will locate any other libraries required by libtool.
It is also possible to link ECho applications without libtool. If this is done, the libraries that ECho depends upon must be specified explicitly. A typical library spec might be ``-lecho -lecl -licode -lvcode -lcm -latl'', again preceeded by an appropriate ``-Llibdirectory'' flag. However there are some subtleties that may cause difficulties. In particular, on many platforms, the linker will preferentially use the shared library if it is available. So, if both a .a and .so file are available in ``libdirectory'', the .so form will be used with implications describe in the next subsection.
The principal caveat to using static libraries is that CM uses program-controlled dynamic linking (dlopen-style) to load its network transport layer. On some platforms, statically linked programs cannot use dlopen(). If CM is unable to load its transport layer, your program will exit with the error ``Failed to initialize default transport. Exiting.''. You may be able to avoid this by linking only some libraries statically and letting others, particularly libc, be dynamic. libtool users can produce a completely statically linked executable because CM uses libtool's ltdl library. That library is capable of simulating dynamic linking in a statically linked environment (if all the dlls are known at link time.) See the libtool docs for how this works.