TIP: Click on subject to list as thread! ANSI
echo: os2prog
to: Jonathan de Boyne Pollar
from: Denis Tonn
date: 1998-09-24 15:39:10
subject: How do DLLs load and unl

Original from  Jonathan de Boyne Pollard  to Denis Tonn on 09-21-1998
Original Subject: How do DLLs load and unlo

                         ---------------------------------------

JP> I'm trying to figure out something, part of which you, with 
JP> your knowledge of the internals of OS/2, may be able to 
JP> help me with.
JP> 
JP> How are DLLs loaded and unloaded ?  In particular, how does OS/2 Warp keep 
JP> track of which DLL_InitTerm functions it needs to call when 
JP> executing DosFreeModule ?  It seems to me that there is a 

 DosFreeModule takes a handle to a module. This is an index for an MTE
(Module Table Entry). There is one MTE per module loaded, regardless
of how many processes it is mapped into (also applies to EXE and other
modules). The system can also locate all the modules (actually
addresses) available to a process and map them to associated MTEs. 
 Once the InitTerm (term) has returned, the module is then "unmapped" 
from the process (asynchronously at some release levels) and it's use 
count decremented. It may still remain in the "system" if the use
count if not zero. 

JP> chicken-and-egg problem here.  It cannot know which 
JP> InitTerm functions to call before it starts unloading 
JP> modules from the address space, but it cannot unload the 
JP> modules from the address space since they must remain 
JP> mapped so that their InitTerm functions can be called.  How 
JP> does OS/2 solve this ?

 InitTerm is called before the module is released from the process 
address space. A dll may have to free private or shared address ranges
as part of it's cleanup. 

 If you are asking about the sequence that each DLL's InitTerm are 
called during process end, I would have to check into it. I suspect it
is the reverse of the load sequence.. InitTerm may not always be
called (abnormal termination), which is where exception handlers and
exitlists come into play.. 

JP> If you are about to tell me that OS/2 uses callbacks into ring 3 from ring 0 
JP> in order to call the InitTerm functions, how does it 
JP> *return* from those callbacks into ring 0 ?  And how does 

 Yep, it calls ring 3 from ring 0, and sets up a return address on the
stack that points into DOSCALL1. The code in DOSCALL1 then gets back 
to ring 0 through a callgate (actually, the stack setup is done in
DOSCALL1). Simple stack manipulation .. 
 All this is done from within the context of a process. Kernel mode is
not required (even though ring 0 code is involved).
 This kind of callback to Ring 3 from Ring 0 is needed in all kinds of 
places (exception handling, exitlist processing, etc). 

JP> it cope with the pathological, but permissible, case that 
JP> the InitTerm function of a module may itself call 
JP> DosLoadModule or DosFreeModule ?  Or the equally 

 Calling DosLoadModule from within an init function is not all that 
pathological, a dll may require other dll functions too.. Likewise 
calling DosFreeModule from within term is just as valid. The sequences
that the kernel and doscall1 follows are the same..
 Doing it the other way is what I would call "pathological". I can't
see a use for freeing a module during init, and the loading of a
module during term would just add it to the process for the duration 
of the cleanup (and it's term would eventually get called). It's
possible to create a loop here during cleanup. I don't know if there 
are any checks to prevent this. Term is called at process cleanup even
if the app does not explicitly free the dll, as part of DosExit
processing.  

 The loader will automaticly do a DosLoadModule (and fixup) for any 
modules referenced in the header of the executable. I call this "load
time" linking vs "run time" linking done with an explicit
DosLoadModule and DosQueryProcAddr from within the app.
 I don't like to use the terms "static" or "dynamic"
linking here,
they can have slightly different connotations in the context of a 
compiler and it's run time libraries.. 

JP> pathological case that the InitTerm function, either 
JP> accidentally or deliberately, never returns at all (leaving 
JP> the kernel internals in an intermediate state) ?

 All this is really process related, not "kernel" related. Many of 
the control blocks for the process are contained in kernel address 
space (heap), but are still related to a specific process. 
 If the term function "does not return", then the module is not freed 
from the process, and the process can not end. You can do similar 
kinds of things in exit handlers.. The "kernel" is unaffected, just 
the process is in an "incomplete" state. As soon as the dll returns
(via doscall1 address on the stack), the kernel and/or doscall1 takes 
the next step in the flow. 
 Think of the case of a DosStartThread where the thread runs totally 
in DLL code, possibly started in the init function of the DLL. The 
term function may have to wait until the started thread reaches a 
"stable" state before it terminates the thread and returns. The 
secondary thread may be working with private addresses, shared 
addresses, files, pipes, etc.. 

 I think if you reconsider your question with a couple of thoughts in 
mind that it will all fall into place. 

 A) DOSCALL1 return addresses are involved in the ring0 > ring3 >ring0 
transition. Doscall1 gets back to Ring0 through a call gate. 
 B) All this is process related, not "system" related. The module is 
not freed from the system until the references to the module are zero.
There is one MTE for every module loaded, regardless of how many 
process references there are to that module. 
 C) InitTerm are called in the context of the process. Ring 0 is not
always "Kernel mode". 


BTW, Not directly related but: I have discussed it a couple of times 
before, still it might be worth mentioning again. All modules (EXE, 
DLL, SYS, etc) have an MTE. The system will do page mapping of the
readonly pages of this module across as many processes as that module
exists in. It does not matter if the module loads in the "private"
address space or not.
 EG: x:\OS2\CMD.EXE loads into the private address space, multiple 
processes using x:\OS2\CMD.EXE will "share" the readonly pages of 
CMD.EXE (all code and readonly pages) implicitly. The way the system 
determines if this is possible is via the fullpathname of the module 
(contained in the MTE). If the MTE already exists in the system the 
loader will only load the writable portions of the executable into the
new process and "map" the readonly pages into the process from 
existing pages (and update the use count in the MTE). 
 If you had 2 copies of CMD.EXE in \os2 and in \os2\bin, and 2 
processes used each of these modules they would NOT be "code page 
shared". They would have separate MTEs, even if "module" is the same
code. This has implications for those people running multiple copies
of the same program (BBS sysops are one category). Less memory will be
used if the SAME copy (full path name!) of the executable is used in
all the processes. Copying a complete directory and modifying the
config files in the new directory is a common way of adding a process,
but keep the executables in one common directory and explicitly point
to them. 

 DLLs are exempt from the above kind of fullpath MTE search, you 
cannot load 2 different DLLs of the same name into the system. Also, 
Dos code running in a VDM cannot be shared this way (Dos "code" is 
writable!)



   Denis       

 All opinions are my very own, IBM has no claim upon them
. 
. 
.
 

 



--- Maximus/2 3.01
* Origin: T-Board - (604) 277-4574 (1:153/908)
SEEN-BY: 396/1 632/0 371 633/210 260 267 270 371 635/506 728 639/252 670/218
@PATH: 153/908 8086 800 140/1 12/12 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™.