Ignore:
Timestamp:
Mar 9, 2000, 8:03:23 PM (25 years ago)
Author:
sandervl
Message:

Dll dependency changes

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/kernel32/windllbase.cpp

    r3005 r3059  
    1 /* $Id: windllbase.cpp,v 1.10 2000-03-04 19:52:36 sandervl Exp $ */
     1/* $Id: windllbase.cpp,v 1.11 2000-03-09 19:03:20 sandervl Exp $ */
    22
    33/*
     
    66 * Copyright 1998-1999 Sander van Leeuwen (sandervl@xs4all.nl)
    77 *
    8  * TODO: Unloading of system dlls is not correct for the PE loader
    9  *       (they're always put at the head of the list even though there
    10  *        might be a dependency with a win32 dll)
     8 * Unloading of a dll always happens in order of dependency (taking nr of
     9 * loads into account)
     10 * Unloading of dynamically loaded dll (with LoadLibrary) in deleteAll
     11 * is done in LIFO order (NT exhibits the same behaviour)
     12 *           
     13 * RemoveCircularDependency: TODO: Send process detach message here??
    1114 *
    1215 * Project Odin Software License can be found in LICENSE.TXT
     
    2629#include <fstream.h>
    2730#include <misc.h>
    28 #include <win32type.h>
     31#include <win32api.h>
    2932#include <pefile.h>
    3033#include <windllbase.h>
     
    4851                           Win32ImageBase *parent)
    4952                 : Win32ImageBase(hinstance),
    50                    referenced(0), fSkipEntryCalls(FALSE),
    51                    fAttachedToProcess(FALSE), fUnloaded(FALSE), fDynamicLoad(FALSE)
     53                   referenced(0), fSkipEntryCalls(FALSE), next(NULL), fInserted(FALSE),
     54                   fAttachedToProcess(FALSE), fUnloaded(FALSE),
     55                   nrDynamicLibRef(0), fLoadLibrary(FALSE), fDisableUnload(FALSE)
    5256{
    5357  dllEntryPoint = DllEntryPoint;
    5458
    55   dlllistmutex.enter();
    56   //unload of dlls needs to be done in reverse order of dependencies
    57   //Note: Only necessary for pe loader; the OS/2 loader takes care of this
    58   //for win32k/pe2lx
    59   if(parent && parent->isDll()) {
    60         Win32DllBase *dll = head;
    61         while(dll) {
    62                 if(dll->getInstanceHandle() == parent->getInstanceHandle()) {
    63                         break;
    64                 }
    65                 dll = dll->next;
    66         }
    67         if(dll) {
    68                 //insert this dll in list after it's parent
    69                 next = dll->next;
    70                 dll->next = this;
    71         }
    72         else    DebugInt3();
    73   }
    74   else {
    75         next = head;
    76         head = this;
    77   }
    78   dlllistmutex.leave();
    79 
    80 #ifdef DEBUG_ENABLELOG_LEVEL2
    81   dlllistmutex.enter();
    82   Win32DllBase *dll = head;
    83 
    84   dprintf2(("Win32DllBase::Win32DllBase: List of loaded dlls:"));
    85   while(dll) {
    86         dprintf2(("DLL %s", dll->szModule));
    87         dll = dll->next;
    88   }
    89   dlllistmutex.leave();
    90 #endif
    91 
     59  setUnloadOrder(parent);
     60 
    9261  dprintf(("Win32DllBase::Win32DllBase %x %s", hinstance, szModule));
    9362}
     
    12291}
    12392//******************************************************************************
    124 //ASSUMPTION: called by FreeLibrary
     93//******************************************************************************
     94void Win32DllBase::loadLibrary()
     95{
     96  //dummy
     97}
     98//******************************************************************************
     99//******************************************************************************
     100void Win32DllBase::incDynamicLib()
     101{
     102  if(nrDynamicLibRef == 0) {
     103        dlllistmutex.enter();
     104        loadLibDlls.Push((ULONG)this);
     105        dlllistmutex.leave();
     106  }
     107  nrDynamicLibRef++;
     108}
     109//******************************************************************************
     110//******************************************************************************
     111void Win32DllBase::decDynamicLib()
     112{
     113  nrDynamicLibRef--;
     114  if(nrDynamicLibRef == 0) {
     115        dlllistmutex.enter();
     116        loadLibDlls.Remove((ULONG)this);
     117        dlllistmutex.leave();
     118  }
     119}
     120//******************************************************************************
     121//unload of dlls needs to be done in reverse order of dependencies
     122//Note: Only necessary for pe loader; the OS/2 loader takes care of this
     123//for win32k/pe2lx
     124//******************************************************************************
     125void Win32DllBase::setUnloadOrder(Win32ImageBase *parent)
     126{
     127 Win32DllBase *dll;
     128 Win32DllBase *parentdll = NULL;
     129
     130  dlllistmutex.enter();
     131  if(parent) {
     132        dll = head;
     133        while(dll) {
     134                if(dll->getInstanceHandle() == parent->getInstanceHandle()) {
     135                        parentdll = dll;
     136                        break;
     137                }
     138                dll = dll->next;
     139        }
     140  }
     141
     142  //first check if this dll is already at a lower position (further down the list)
     143  //than the parent
     144  if(parentdll && fInserted) {//already in the list?
     145        dll = parentdll->next;
     146        while(dll) {
     147                if(dll->getInstanceHandle() == getInstanceHandle()) {
     148                        dlllistmutex.leave();
     149                        return; //it's at a lower position, so no need to change anything
     150                }
     151                dll = dll->next;
     152        }
     153
     154        //it's already in the list but not at the right position; remove it now
     155        if(head == this) {
     156                head = next;
     157        }
     158        else {
     159                dll = head;
     160                while(dll->next) {
     161                        if(dll->next == this) {
     162                                dll->next = next;
     163                                break;
     164                        }
     165                        dll = dll->next;
     166                }
     167        }
     168  }
     169  else
     170  if(fInserted) {//already in the list?
     171        dlllistmutex.leave();
     172        return;
     173  }
     174  //(re)insert it in the list after it's parent
     175  if(parentdll) {
     176        next = parentdll->next;
     177        parentdll->next = this;
     178  }
     179  else {//no parent or exe, just add it at the start of the list
     180        next = head;
     181        head = this;
     182  }
     183  fInserted = TRUE;
     184
     185  //Now do the same thing for the child dependencies
     186  QueueItem *item;
     187
     188  item = loadedDlls.Head();
     189  while(item) {
     190        dll = (Win32DllBase *)loadedDlls.getItem(item);
     191        //Check for circular dependencies (i.e. in Lotus Notes)
     192        if(dll != parentdll) {
     193                dll->setUnloadOrder(this);
     194        }
     195
     196        item  = loadedDlls.getNext(item);
     197  }
     198
     199  dlllistmutex.leave();
     200}
     201//******************************************************************************
     202//******************************************************************************
     203#ifdef DEBUG
     204ULONG Win32DllBase::AddRef(char *parentname)
     205#else
     206ULONG Win32DllBase::AddRef()
     207#endif
     208{
     209 Win32DllBase *dll;
     210
     211  dprintf(("Win32DllBase::AddRef %s->%s %d", parentname, getModuleName(), referenced+1));
     212  ++referenced;
     213#ifdef DEBUG
     214  if(referenced == 1) {
     215#ifdef DEBUG_ENABLELOG_LEVEL2
     216        printListOfDlls();
     217#endif
     218        //printDependencies(NULL);
     219  }
     220#endif
     221
     222  return referenced;
     223}
     224//******************************************************************************
    125225//******************************************************************************
    126226ULONG Win32DllBase::Release()
    127227{
    128  ULONG ret = --referenced;
    129 
    130   if(ret == 0) {
    131         dprintf(("Win32DllBase::Release, referenced == 0\n"));
     228 Queue         queue;
     229 QueueItem    *item;
     230 Win32DllBase *dll;
     231 LONG          ret;
     232
     233  dprintf(("Win32DllBase::Release %s %d", getModuleName(), referenced-1));
     234
     235  ret = --referenced;
     236  if(ret <= 0) {
     237        //make copy of linked list of dependencies
     238        queue = loadedDlls;
     239
     240        //remove any circular dependencies on this dll that might be present
     241        item = queue.Head();
     242        while(item) {
     243                dll = (Win32DllBase *)queue.getItem(item);
     244                if(dll == NULL) {
     245                        dprintf(("ERROR: Win32DllBase::Release: dll item == NULL!!"));
     246                        DebugInt3();
     247                        return -1;
     248                }
     249                dll->RemoveCircularDependency(this);
     250                item = queue.getNext(item);
     251        }
     252#ifdef DEBUG
     253        //printDependencies(NULL);
     254#endif
     255        dprintf(("Win32DllBase::Release %s referenced == 0", getModuleName()));
     256
     257        //delete dll object
    132258        delete this;
     259
     260        //unreference all of it's dependencies
     261        item = queue.Head();
     262        while(item) {
     263                dll = (Win32DllBase *)queue.getItem(item);
     264                if(dll == NULL) {
     265                        dprintf(("ERROR: Win32DllBase::Release: dll item == NULL!!"));
     266                        DebugInt3();
     267                        return -1;
     268                }
     269                dll->Release();
     270                item = queue.getNext(item);
     271        }
    133272  }
    134273  return(ret);
    135274}
     275//******************************************************************************
     276//Lotus Notes has several ugly circular dependencies in it's dlls.
     277//Remove them before they cause problems.
     278//******************************************************************************
     279BOOL Win32DllBase::RemoveCircularDependency(Win32DllBase *parent)
     280{
     281 QueueItem    *item, *tmp;
     282 Win32DllBase *dll;
     283 BOOL          ret = FALSE;
     284
     285  //remove any circular dependencies on this dll that might be present
     286  item = loadedDlls.Head();
     287  while(item) {
     288        dll = (Win32DllBase *)loadedDlls.getItem(item);
     289        if(dll == NULL) {
     290                dprintf(("ERROR: Win32DllBase::Release: dll item == NULL!!"));
     291                DebugInt3();
     292                return FALSE;
     293        }
     294        tmp = loadedDlls.getNext(item);
     295        if(dll == parent) {
     296                dprintf(("Removing CIRCULAR dependency %s->%s", parent->getModuleName(), dll->getModuleName()));
     297                loadedDlls.Remove(item);
     298                ret = TRUE;
     299        }
     300////    else    ret |= dll->RemoveCircularDependency(parent);
     301        item = tmp;
     302  }
     303  //TODO: Send process detach message here??
     304  return ret;
     305}
     306//******************************************************************************
     307//There's a slight problem with our dependency procedure.
     308//example: gdi32 is loaded -> depends on kernel32 (which is already loaded)
     309//         kernel32's reference count isn't updated
     310//         (when we load gdi32, we don't know which dlls it depends on and which
     311//          of those are already loaded and which aren't)
     312//-> solution: Determine reference counts of dependant lx dlls and update those
     313//             reference counts
     314//******************************************************************************
     315void Win32DllBase::updateDependencies()
     316{
     317 QueueItem    *item;
     318 Win32DllBase *dll, *depdll;
     319 ULONG         refcount;
     320 
     321  dlllistmutex.enter();
     322  item = loadedDlls.Head();
     323  while(item) {
     324        depdll   = (Win32DllBase *)loadedDlls.getItem(item);
     325        if(depdll == NULL) {
     326                dprintf(("updateDependencies: depdll == NULL!!"));
     327                DebugInt3();   
     328                return;
     329        }
     330        refcount = 0;
     331        dll      = head;
     332
     333        while(dll) {
     334                if(dll->dependsOn(depdll)) {
     335                        refcount++;
     336                }
     337                dll = dll->getNext();
     338        }
     339        if(refcount > depdll->referenced) {
     340                dprintf(("Win32DllBase::updateDependencies changing refcount of %s to %d (old=%d)", depdll->getModuleName(), refcount, depdll->referenced));
     341                depdll->referenced = refcount;
     342        }
     343
     344        item = loadedDlls.getNext(item);
     345  }
     346  dlllistmutex.leave();
     347}
     348//******************************************************************************
     349//******************************************************************************
     350#ifdef DEBUG
     351void Win32DllBase::printDependencies(char *parent)
     352{
     353 QueueItem    *item;
     354 Win32DllBase *dll;
     355 ULONG         ret;
     356
     357  dprintf(("Dependency list: %s->%s %d", parent, getModuleName(), referenced));
     358  item = loadedDlls.Head();
     359  while(item) {
     360        dll = (Win32DllBase *)loadedDlls.getItem(item);
     361        if(dll == NULL) {
     362                return;
     363        }
     364        dll->printDependencies(getModuleName());
     365        item = loadedDlls.getNext(item);
     366  }
     367}
     368//******************************************************************************
     369//******************************************************************************
     370#ifdef DEBUG_ENABLELOG_LEVEL2
     371void Win32DllBase::printListOfDlls()
     372{
     373 Win32DllBase *dll;
     374
     375  dll = head;
     376
     377  dprintf2(("Win32DllBase::Win32DllBase: List of loaded dlls:"));
     378  while(dll) {
     379        dprintf2(("DLL %s %d", dll->szModule, dll->referenced));
     380        dll = dll->next;
     381  }
     382}
     383#endif
     384#endif
    136385//******************************************************************************
    137386//******************************************************************************
     
    252501void Win32DllBase::attachThreadToAllDlls()
    253502{
     503  dlllistmutex.enter();
    254504  Win32DllBase *dll = Win32DllBase::head;
    255505  while(dll) {
     
    257507        dll = dll->getNext();
    258508  }
     509  dlllistmutex.leave();
    259510}
    260511//******************************************************************************
     
    263514void Win32DllBase::detachThreadFromAllDlls()
    264515{
     516  dlllistmutex.enter();
    265517  Win32DllBase *dll = Win32DllBase::head;
    266518  while(dll) {
     
    268520        dll = dll->getNext();
    269521  }
     522  dlllistmutex.leave();
    270523}
    271524//******************************************************************************
     
    274527void Win32DllBase::tlsAttachThreadToAllDlls()
    275528{
     529  dlllistmutex.enter();
    276530  Win32DllBase *dll = Win32DllBase::head;
    277531  while(dll) {
     
    279533        dll = dll->getNext();
    280534  }
     535  dlllistmutex.leave();
    281536}
    282537//******************************************************************************
     
    285540void Win32DllBase::tlsDetachThreadFromAllDlls()
    286541{
     542  dlllistmutex.enter();
    287543  Win32DllBase *dll = Win32DllBase::head;
    288544  while(dll) {
     
    290546        dll = dll->getNext();
    291547  }
    292 }
    293 //******************************************************************************
    294 //******************************************************************************
    295 void Win32DllBase::deleteAll(BOOL fDynamicLoad)
    296 {
    297  Win32DllBase *dll = Win32DllBase::head, *tmp;
    298 
    299 #ifdef DEBUG
    300   dlllistmutex.enter();
    301 
    302   dprintf(("Win32DllBase::deleteAll: List of loaded dlls:"));
     548  dlllistmutex.leave();
     549}
     550//******************************************************************************
     551//******************************************************************************
     552void Win32DllBase::deleteAll()
     553{
     554 Win32DllBase *dll = Win32DllBase::head;
     555
     556  dprintf(("Win32DllBase::deleteAll"));
     557
     558#ifdef DEBUG_ENABLELOG_LEVEL2
     559  if(dll) dll->printListOfDlls();
     560#endif
     561
     562  dlllistmutex.enter();
    303563  while(dll) {
    304         dprintf(("DLL %s", dll->szModule));
    305         dll = dll->next;
    306   }
    307   dlllistmutex.leave();
    308   dll = Win32DllBase::head;
     564        dll->Release();
     565        dll = Win32DllBase::head;
     566  }
     567  dlllistmutex.leave();
     568  dprintf(("Win32DllBase::deleteAll Done!"));
     569}
     570//******************************************************************************
     571//Delete dlls loaded by LoadLibrary(Ex) in LIFO order
     572//******************************************************************************
     573void Win32DllBase::deleteDynamicLibs()
     574{
     575 Win32DllBase *dll = head;
     576 QueueItem    *item;
     577
     578  dprintf(("Win32DllBase::deleteDynamicLibs"));
     579#ifdef DEBUG_ENABLELOG_LEVEL2
     580  if(dll) dll->printListOfDlls();
    309581#endif
    310582
    311   while(dll) {
    312         if(fDynamicLoad || !dll->fDynamicLoad) {
    313                 tmp = dll->next;
    314                 dll->Release();
    315                 dll = tmp;
    316         }
    317         else    dll = dll->next;
    318   }
     583  dlllistmutex.enter();
     584
     585  item = loadLibDlls.Head();
     586  while(item) {
     587        dll = (Win32DllBase *)loadLibDlls.getItem(item);
     588        int dynref = dll->nrDynamicLibRef;
     589        if(dynref) {
     590                while(dynref) {
     591                        dynref--;
     592                        dll->decDynamicLib();
     593                        dll->Release();
     594                }
     595        }
     596        else    DebugInt3();
     597        item = loadLibDlls.Head(); //queue could have been changed, so start from the beginning
     598  }
     599
     600  dlllistmutex.leave();
     601}
     602//******************************************************************************
     603//******************************************************************************
     604Win32DllBase *Win32DllBase::getFirst()
     605{
     606  return head;
    319607}
    320608//******************************************************************************
     
    386674//******************************************************************************
    387675//******************************************************************************
    388 Win32DllBase *Win32DllBase::findModule(char *dllname)
     676Win32DllBase *Win32DllBase::findModule(char *dllname, BOOL fRenameFirst)
    389677{
    390678 Win32DllBase *dll;
     
    392680 char *dot, *temp;
    393681
    394   dprintf(("findModule %s", dllname));
     682////  dprintf2(("findModule %s", dllname));
    395683
    396684  strcpy(szDllName, OSLibStripPath(dllname));
    397685  strupr(szDllName);
     686
     687  if(fRenameFirst) {
     688        renameDll(szDllName, FALSE);
     689  }
     690
    398691  dot = strstr(szDllName, ".");
    399692  if(dot)
     
    417710Win32DllBase *Win32DllBase::findModule(WIN32DLLENTRY DllEntryPoint)
    418711{
    419    dprintf(("findModule %X", DllEntryPoint));
     712   dprintf2(("findModule %X", DllEntryPoint));
    420713
    421714   dlllistmutex.enter();
     
    468761//******************************************************************************
    469762Win32DllBase *Win32DllBase::head = NULL;
     763Queue         Win32DllBase::loadLibDlls;
Note: See TracChangeset for help on using the changeset viewer.