                EMX single-threaded C runtime DLL replacement
                ---------------------------------------------

    Legal issues
    ------------

    The program is provided AS-IS, without any explicit or
    implicit guaranties.

    It works for me, but it is not guaranteed it to work for you.

    If you run a power plant, DONT use this program (I believe if you
    really run a power plant or such you're not a fool to use PC even).


    Installation
    ------------

    Installation is pretty simple: just copy dll/emxlibcs.dll over the
emxlibcs.dll file in emx/dll directory. If it is in use by another program,
use some tool to unlock it, or reboot to the command prompt (Alt+F1/C) then
copy it. Of course you may want to back up the old emxlibcs.dll before you
do it, although you should notice no difference between the old emxlibcs and
the replacement.


    Introduction
    ------------

    Why I need this strange thing?  -- you may ask.  Well, if you're just a
user, it is likely that you don't need it (except if some program you are
installing explicitely requires it).  If you're a programmer and use EMX
developement environment, and even more, you are porting miscelaneous Unix
software to XFree86/2, this is a must.  I will explain why.

    With the introduction of OS/2 port of XFree86 we (the community of OS/2
programmers) have faced yet another (in)compatibility (or even confusion)
issue:  the impossibility to use single-threaded and multiple-threaded
versions of EMX C runtime DLLs at once.  Since XFree86 was compiled with
"-Zcrtdll -Zmt" basically it means you have to compile ALL your programs and
DLLs with -Zmt.  But this is a nonsence!  Most Unix programs are
single-threaded by nature, besides there already exists a lot of compiled
stuff -- which have to be recompiled if you want to use it with X11 programs?!
Even worse - say someone has a precompiled version of PNG.DLL or JPEG.DLL
installed -- and your X11 program requires them, but he actually has the
SINGLE-threaded version of those DLLs.  So the result is awful:  the program
crashes, user complains that your program is shit, everybody is confused.


    Analysis
    --------

    Let's understand why exactly EMXLIBCM and EMXLIBCS runtimes are
incompatible.  Let's suppose we have a typical case:  we wrote a single -
threaded program that uses one single-threaded library and one multi -
threaded dynamic library (sometimes we even may not know that second
DLL is linked against multi-threaded C runtime).

                                  +---------+
                                  | program |
                                  +----+----+
                                       |
                     +-----------------+-----------------+
                     |                 |                 |
              +------+-------+    +----+----+       +----+----+
              | EMXLIBCS.DLL |<---| DLL one |       | DLL two |
              +--------------+    +---------+       +----+----+
                                                         |
                                                  +------+-------+
                                                  | EMXLIBCM.DLL |
                                                  +--------------+

    In the above picture the program was linked as a single-threaded program,
and "DLL one" is a single-threaded library as well.  Now the "DLL two" is a
multi-threaded DLL, thus it uses EMXLIBCM.DLL.  With the "stock" EMX DLLs this
scheme miserably fails, because EMX C runtimes are absolutely independent,
thus the program has initialized the EMXLIBCS runtime but not the EMXLIBCM
runtime.  The second runtime, being uninitialized, will crash.  But even if we
initialize it somehow, we face another problem:  objects created by one
runtime are unknown to other runtime.  So if, for example, the EMXLIBCM
library opens a file, and returns it somehow to the program (via "DLL two")
then we do from program a fread() on it, EMXLIBCS will get confused - it
doesn't know anything about this file object.

    Besides file objects/handles there are another incompatibility issues -
memory allocation (memory allocated by one runtime cannot be free() by
another), exceptions and so on. Almost every persistent object created by
one runtime is incompatible with another. This is the problem.


    Solution
    --------

    The proposed solution is to bind somehow the two DLLs together.  More
precisely, one of DLLs could be just a thin wrapper around the second DLL.
Fortunately, OS/2 has the notion of so-called "forwarders", that is, one DLL
can forward some (or all) exported functions to another DLL without even
writing a wrapper function, something like

  size_t strlen(char *s)
  {
    return otherdll_strlen (s);
  }

Thus with forwarders we do the above stuff for free, without runtime cost.

    Now the question is:  which runtime should be primary and which should be
just a wrapper? When I have started the project I have intended to leave the
single-threaded EMXLIBCS as-is and make EMXLIBCM as a wrapper around EMXLIBCS,
with the required multi-threaded locks added (not many functions require them,
really). But during developement I have realized two things:

    - EMXLIBCS is almost fully-multithreaded, in reality. This happens because
    EMX.DLL (the core) is multi-threaded itself. EMX.DLL is responsible for
    memory allocation, file handles and so on. The respective locks ARE
    already there.

    - Alas, EMXLIBCS has some internal functions that cannot be safely
    replaced "from outside" with multi-threaded functions. The required
    ties are simply missing from EMXLIBCS exported functions list.

    - Besides, it's just too much unwanted work.

    So I have decided to make it vice versa: make EMXLIBCS a wrapper around
EMXLIBCM. This was *surprisingly* easy to do as I just had to forward all the
functions to EMXLIBCM, without any further hassle.


    The cost
    --------

    Everything in this world comes for a cost.  But sometimes (like in our
case) the cost is really very low.  Since EMX.DLL is already multi-threaded,
the cost for single-threading programs using multi-threaded runtime is almost
zero. There is a very small number of functions that could really benefit from
being really single-threaded, I even can't remember one to list it here.

    For *really* single threaded programs (that is, the programs compiled with
-Zsys) the cost is zero (since they don't use the DLLs). Thus if you really
care for speed, use -Zsys and don't use -Zcrtdll (this applies for 'stock'
EMX as well).

    In fact, to be honest, you will *gain* resources and maybe even speed by
using this EMXLIBCS replacement (it is very hard to objectively evaluate the
real cost, so the logic is purely speculative). The replacement is a lot
smaller (about 200K of code is replaced with 6K). Not to mention the resources
which are allocated separately by both EMXLIBCS and EMXLIBCM and which are
shared if you use this replacement.


    History
    -------

-*- Version 0.0.1
    This is the first release of single-threading runtime fix package.

-*- Version 0.0.2
    Fix for a rarely occuring situation which leads to crashes. This happens
    when a program that uses EMXLIBCM loads (dynamically) some DLL that uses
    EMXLIBCS and then that DLL is unloaded. This leads to a pointer inside
    EMXLIBCM and which is normally redirected to EMXLIBCS to point into the
    void (since EMXLIBCS is gone). Now EMXLIBCS restores that pointer when it
    is unloaded.


    Final
    -----

    Well, there is not much that can be said here. Any comments, suggestions
etc are welcome.

    On my side, I would like to see in future EMX versions just one C runtime
DLL (with one or two forwarder DLLs kept for backward compatibility).

Andrew Zabolotny,
  <bit@eltech.ru>
