TIP: Click on subject to list as thread! ANSI
echo: os2prog
to: Mario Semo
from: Jonathan de Boyne Pollard
date: 1998-10-06 09:12:36
subject: How do DLLs load and unload ?

JdBP>> How are DLLs loaded and unloaded ?  In particular, how does OS/2
 JdBP>> Warp keep track of which DLL_InitTerm functions it needs to call
 JdBP>> when executing DosFreeModule ?  It seems to me that there is a

 MS> whats the problem? theoretical a simple recursive logic:

 MS>   unloadDLL(...)
 MS>   {
 MS>    list_of_required_dlls *list;
 MS>    for all elements in list do unloadDLL(element)
 MS> ** unload from memory
 MS>    done
 MS>   }

This much is obvious.  But, unfortunately, it glibly skips over some very
important details, the very ones that I am actually asking about, in the
step that I have marked with the "**".  

For example, it doesn't in any way clarify what happens with respect to
locking and unlocking the per-process and system module tables.  In
particular, how does it cope with a recursive call into DosFreeModule from
within the termination function of a DLL.  Would the kernel deadlock itself
?  Or would it simply corrupt the module graph ?  Or is the locking
fine-grained ?  If the latter, what are the objects that are locked ?

For another example, it doesn't clarify whether the DLL's memory objects
are unmapped from the address space immediately, i.e. it really is the
single-pass algorithm that the above simplified pseudo-code makes it appear
to be, or whether there is in fact a *two*-stage process involved (stage 1
recursively descending the module graph and calling the termination
functions, and stage 2 performing a second recursive descent to perform the
actual unmapping).  

Incidentally, your quote from Roger Pett:

 RP> We get away with this because the OS doesn't immediately unload the 
 RP> DLL after running the DLL termination.

would imply that indeed OS/2 *does* use a two-pass algorithm, because it
implies that all of the InitTerm functions are called before any of the
memory objects are actually unmapped.  

To modify your pseudo-code a bit, this would imply something like:

    RecursiveTerminate(module)
    {
        if (--module.referencecount == 0) {
            Ring3Callback(module.InitTerm) ;
            for m <- module.all_referenced_modules()
                RecursiveTerminate(m) ;
        }
    }

    RecursiveUnmap(module)
    {
        if (module.referencecount == 0) {
            unmap all memory objects for this module from the process ;
            for m <- module.all_referenced_modules()
                RecursiveUnmap(m) ;
        }
    }

    DosFreeModule(module)
    {
        RecursiveTerminate(module) ;
        RecursiveUnmap(module) ;
    }

This still isn't perfectly re-entrant, though.  And it's unclear, assuming
that we *do* want a fine-grained locking scheme, what objects to lock and
what the duration of those locks should be.

 ¯ JdeBP ®

--- FleetStreet 1.19 NR
* Origin: JdeBP's point, using Squish (2:440/4.3)
SEEN-BY: 396/1 632/0 371 633/210 260 267 270 371 635/506 728 639/252 670/218
@PATH: 440/4 255/1 251/25 396/1 633/260 635/506 728 633/267

SOURCE: echomail via fidonet.ozzmosis.com

Email questions or comments to sysop@ipingthereforeiam.com
All parts of this website painstakingly hand-crafted in the U.S.A.!
IPTIA BBS/MUD/Terminal/Game Server List, © 2025 IPTIA Consulting™.