Index: /trunk/kLdr/kLdr.h
===================================================================
--- /trunk/kLdr/kLdr.h	(revision 2836)
+++ /trunk/kLdr/kLdr.h	(revision 2837)
@@ -731,5 +731,14 @@
 #define KLDR_ERR_INVALID_HANDLE         (KLDR_ERR_BASE + 33)
 /** The module wasn't found. */
-#define KLDR_ERR_MODULE_NOT_FOUND       (KLDR_ERR_BASE + 34)
+#define KLDR_ERR_MODULE_NOT_FOUND                   (KLDR_ERR_BASE + 34)
+/** A prerequisit module wasn't found. */
+#define KLDR_ERR_PREREQUISITE_MODULE_NOT_FOUND      (KLDR_ERR_BASE + 35)
+/** The module is being terminated and can therefore not be loaded. */
+#define KLDR_ERR_MODULE_TERMINATING                 (KLDR_ERR_BASE + 36)
+/** A prerequisit module is being terminated and can therefore not be loaded. */
+#define KLDR_ERR_PREREQUISITE_MODULE_TERMINATING    (KLDR_ERR_BASE + 37)
+/** An allocation failed. */
+#define KLDR_ERR_NO_MEMORY                          (KLDR_ERR_BASE + 38)
+
 
 /** Encountered a bad fixup. */
Index: /trunk/kLdr/kLdrDyld.c
===================================================================
--- /trunk/kLdr/kLdrDyld.c	(revision 2836)
+++ /trunk/kLdr/kLdrDyld.c	(revision 2837)
@@ -89,9 +89,16 @@
  * previous frame.
  */
-PPKLDRDYLDMOD   g_pakLdrDyld;
-/** The number of used entries in the g_pakLdrDyld array. */
-uint32_t        g_ckLdrDyld;
-/** The number of entries allocated for the g_pakLdrDyld array. */
-uint32_t        g_ckLdrDyldAllocated;
+static PPKLDRDYLDMOD    g_papStackMods;
+/** The number of used entries in the g_papStackMods array. */
+static uint32_t         g_cStackMods;
+/** The number of entries allocated for the g_papStackMods array. */
+static uint32_t         g_cStackModsAllocated;
+/** Number of active load calls. */
+static uint32_t         g_cActiveLoadCalls;
+/** Number of active unload calls. */
+static uint32_t         g_cActiveUnloadCalls;
+/** Boolean flag indicating that GC is active. */
+static uint32_t         g_fActiveGC;
+
 
 /** The global error buffer. */
@@ -102,4 +109,5 @@
 /** The executable flags. */
 uint32_t        kLdrDyldFlags;
+
 
 
@@ -116,7 +124,13 @@
 static int kldrDyldDoGetFilename(PKLDRDYLDMOD pMod, char *pszFilename, size_t cchFilename);
 static int kldrDyldDoQuerySymbol(PKLDRDYLDMOD pMod, uint32_t uSymbolOrdinal, const char *pszSymbolName, uintptr_t *pValue, uint32_t *pfKind);
-static void kldrDyldStartLoading(void);
-static void kldrDyldStopLoading(void);
-static int kldrDyldCopyError(int rc, char *pszErr, size_t cchErr);
+
+static void     kldrDyldDoModuleTerminationAndGarabageCollection(void);
+
+static uint32_t kldrDyldStackNewFrame(void);
+int     kldrDyldStackPushModule(PKLDRDYLDMOD pMod);
+static int      kldrDyldStackFrameCompleted(void);
+static void     kldrDyldStackDropFrame(uint32_t iStackTop, uint32_t iStackBottom, int rc);
+
+static int      kldrDyldCopyError(int rc, char *pszErr, size_t cchErr);
 
 
@@ -178,5 +192,8 @@
     {
         PKLDRDYLDMOD pMod = NULL;
+        g_cActiveLoadCalls++;
         rc = kldrDyldDoLoad(pszDll, pszDefPrefix, pszDefSuffix, enmSearch, fFlags, phMod, pszErr, cchErr);
+        g_cActiveLoadCalls--;
+        kldrDyldDoModuleTerminationAndGarabageCollection();
         kldrHlpSemRelease();
         *phMod = pMod;
@@ -203,5 +220,8 @@
     if (!rc)
     {
+        g_cActiveUnloadCalls++;
         rc = kldrDyldDoUnload(hMod);
+        g_cActiveUnloadCalls--;
+        kldrDyldDoModuleTerminationAndGarabageCollection();
         kldrHlpSemRelease();
     }
@@ -217,5 +237,5 @@
  *
  * @returns 0 on success.
- * @returns KLDR_ERR_MODULE_NOT_FOUND on failure.
+ * @returns KLDR_ERR_MODULE_NOT_FOUND or some I/O error on failure.
  * @param   pszDll          The name of the dll to look for.
  * @param   pszDefPrefix    Prefix than can be used when searching.
@@ -383,8 +403,110 @@
 
 
-
-
-/**
- * Worker for kLdrDyldLoad().
+/**
+ * Gets prerequisite module.
+ *
+ * This will try load the requested module if necessary, returning it in the MAPPED state.
+ *
+ * @returns 0 on success.
+ * @returns KLDR_ERR_MODULE_NOT_FOUND or I/O error on failure.
+ * @param   pszDll          The name of the dll to look for.
+ * @param   pszDefPrefix    Prefix than can be used when searching.
+ * @param   pszDefSuffix    Suffix than can be used when searching.
+ * @param   enmSearch       Method to use when locating the module.
+ * @param   fFlags          Flags, a combintation of the KLDRYDLD_LOAD_FLAGS_* \#defines.
+ * @param   pDep            The depentant module.
+ * @param   ppMod           Where to put the module we get.
+ */
+int kldrDyldGetPrerequisite(const char *pszDll, const char *pszDefPrefix, const char *pszDefSuffix, KLDRDYLDSEARCH enmSearch,
+                            unsigned fFlags, PKLDRDYLDMOD pDep, PPKLDRDYLDMOD ppMod)
+{
+    int rc;
+
+    *ppMod = NULL;
+
+    /*
+     * Try find the module among the ones that's already loaded.
+     */
+    rc = kldrDyldFindExistingModule(pszDll, pszDefPrefix, pszDefSuffix, enmSearch, fFlags, ppMod);
+    if (!rc)
+    {
+        /*
+         * See if the module should go on the stack and if it needs
+         * some work before that.
+         */
+        switch ((*ppMod)->enmState)
+        {
+            /*
+             * The module is good, just add the dependency.
+             */
+            case KLDRSTATE_GOOD:
+            case KLDRSTATE_INITIALIZING:
+                return kldrDyldModAddDep(*ppMod, pDep);
+
+            /*
+             * Prerequisites needs checking.
+             */
+            case KLDRSTATE_PENDING_INITIALIZATION:
+                (*ppMod)->fAlreadySeen = 0;
+            case KLDRSTATE_PENDING_TERMINATION:
+                break;
+
+            /*
+             * The module has been terminated so it need to be reloaded, have it's
+             * prereqs loaded, fixed up and initialized before we can use it again.
+             */
+            case KLDRSTATE_PENDING_GC:
+                rc = kldrDyldModReload(*ppMod);
+                if (rc)
+                    return rc;
+                break;
+
+            /*
+             * It's just been loaded or reloaded in this session, we will push it
+             * onto the stack even so to get a consisten init order with the other
+             * states.
+             */
+            case KLDRSTATE_MAPPED:
+            case KLDRSTATE_RELOADED:
+                break;
+
+            /*
+             * Forget it, we don't know how to deal with re-initialization here.
+             */
+            case KLDRSTATE_TERMINATING:
+                KLDRDYLD_ASSERT(!"KLDR_ERR_PREREQUISITE_MODULE_TERMINATING");
+                return KLDR_ERR_PREREQUISITE_MODULE_TERMINATING;
+
+            /*
+             * Invalid state.
+             */
+            default:
+                KLDRDYLD_ASSERT(!"invalid state");
+                break;
+        }
+    }
+    else
+    {
+        /*
+         * We'll have to load it from file.
+         */
+        rc = kldrDyldFindNewModule(pszDll, pszDefPrefix, pszDefSuffix, enmSearch, fFlags, ppMod);
+        if (!rc)
+            rc = kldrDyldModMap(*ppMod);
+    }
+
+    /*
+     * Push it onto the stack and add the dependency.
+     */
+    if (!rc)
+        rc = kldrDyldStackPushModule(*ppMod);
+    if (!rc)
+        rc = kldrDyldModAddDep(*ppMod, pDep);
+    return rc;
+}
+
+
+/**
+ * Worker for kLdrDyldLoad() and helper for kLdrDyldLoadExe().
  * @internal
  */
@@ -392,8 +514,8 @@
                           unsigned fFlags, PPKLDRDYLDMOD ppMod, char *pszErr, size_t cchErr)
 {
-    int rc;
-
-    /*
-     * Try find it among the modules that's already loaded.
+    int         rc;
+
+    /*
+     * Try find the module among the ones that's already loaded.
      */
     rc = kldrDyldFindExistingModule(pszDll, pszDefPrefix, pszDefSuffix, enmSearch, fFlags, ppMod);
@@ -401,24 +523,182 @@
     {
         /*
-         * If we're in a module termination call we must check that all the modules we
-         * depend on are loaded and initialized.
+         * Because of initialization and termination routines this
+         * get's kind of complicated. Even if the module is loaded,
+         * we might end up having to resolve all dependencies to check
+         * whether reloading or/and initialization is required.
          */
-//continue here        if ((*ppMod)->enmState::KLDRSTATE_LOADED)
+        switch ((*ppMod)->enmState)
         {
-            kldrHlpAssert(!"implement me");
+            /*
+             * Prerequisites are ok, so nothing to do really.
+             */
+            case KLDRSTATE_GOOD:
+            case KLDRSTATE_INITIALIZING:
+                return kldrDyldModDynamicLoad(*ppMod);
+
+            /*
+             * Prerequisites needs checking.
+             */
+            case KLDRSTATE_PENDING_INITIALIZATION:
+                (*ppMod)->fAlreadySeen = 0;
+            case KLDRSTATE_PENDING_TERMINATION:
+                break;
+
+            /*
+             * The module has been terminated so it need to be reloaded, have it's
+             * prereqs loaded, fixed up and initialized before we can use it again.
+             */
+            case KLDRSTATE_PENDING_GC:
+                rc = kldrDyldModReload(*ppMod);
+                if (rc)
+                    return kldrDyldCopyError(rc, pszErr, cchErr);
+                break;
+
+            /*
+             * Forget it, we don't know how to deal with re-initialization here.
+             */
+            case KLDRSTATE_TERMINATING:
+                KLDRDYLD_ASSERT(!"KLDR_ERR_MODULE_TERMINATING");
+                return KLDR_ERR_MODULE_TERMINATING;
+
+            /*
+             * Invalid state.
+             */
+            default:
+                KLDRDYLD_ASSERT(!"invalid state");
+                break;
         }
-        return kldrDyldModDynamicLoad(*ppMod);
-    }
-
-    /*
-     * Try open it.
-     */
-    kldrDyldStartLoading();
-    rc = kldrDyldFindNewModule(pszDll, pszDefPrefix, pszDefSuffix, enmSearch, fFlags, ppMod);
+    }
+    else
+    {
+        /*
+         * We'll have to load it from file.
+         */
+        rc = kldrDyldFindNewModule(pszDll, pszDefPrefix, pszDefSuffix, enmSearch, fFlags, ppMod);
+        if (rc)
+            return kldrDyldCopyError(rc, pszErr, cchErr);
+        rc = kldrDyldModMap(*ppMod);
+    }
+
     if (!rc)
     {
-
-
-    }
+        /*
+         * Create the stack frame of modules by resolving module prerequisites.
+         */
+        uint32_t iStackBottom = kldrDyldStackNewFrame();
+        uint32_t iStack = iStackBottom;
+        uint32_t iStackTop;
+        rc = kldrDyldStackPushModule(*ppMod);
+        while (!rc && iStack < g_cStackMods /* changes while we're in the loop */)
+        {
+            PKLDRDYLDMOD pMod = g_papStackMods[iStack];
+            switch (pMod->enmState)
+            {
+                /*
+                 * Load immediate prerequisite modules and push the ones needing
+                 * attention onto the stack.
+                 */
+                case KLDRSTATE_MAPPED:
+                case KLDRSTATE_RELOADED:
+                    rc = kldrDyldModLoadPrerequisites(pMod, pszDll, pszDefPrefix, pszDefSuffix, enmSearch, fFlags);
+                    break;
+
+                /*
+                 * Check dependencies.
+                 */
+                case KLDRSTATE_PENDING_TERMINATION:
+                    rc = kldrDyldModCheckPrerequisites(pMod);
+                    break;
+
+                /*
+                 * Check its prerequisite modules the first time around.
+                 */
+                case KLDRSTATE_PENDING_INITIALIZATION:
+                    if (!pMod->fAlreadySeen)
+                    {
+                        pMod->fAlreadySeen = 1;
+                        rc = kldrDyldModCheckPrerequisites(pMod);
+                    }
+                    break;
+
+                /*
+                 * These are ok.
+                 */
+                case KLDRSTATE_LOADED_PREREQUISITES:
+                case KLDRSTATE_INITIALIZING:
+                case KLDRSTATE_GOOD:
+                    break;
+
+                /*
+                 * All other stats are invalid.
+                 */
+                default:
+                    KLDRDYLD_ASSERT(!"invalid state");
+                    break;
+            }
+
+            /* next */
+            iStack++;
+        }
+        iStackTop = kldrDyldStackFrameCompleted();
+
+        /*
+         * Apply fixups.
+         */
+        for (iStack = iStackBottom; !rc && iStack < iStackTop; iStack++)
+        {
+            PKLDRDYLDMOD pMod = g_papStackMods[iStack];
+            if (pMod->enmState == KLDRSTATE_LOADED_PREREQUISITES)
+                rc = kldrDyldModFixup(pMod);
+
+        }
+#ifdef KLDRDYLD_STRICT
+        if (!rc)
+            for (iStack = iStackBottom; !rc && iStack < iStackTop; iStack++)
+                KLDRDYLD_ASSERT(g_papStackMods[iStack]->enmState >= KLDRSTATE_FIXED_UP);
+#endif
+
+        /*
+         * Call the initializers (LIFO order).
+         */
+        iStack = iStackBottom;
+        while (!rc && iStack-- > iStackTop)
+        {
+            PKLDRDYLDMOD pMod = g_papStackMods[iStack];
+            if (pMod->enmState == KLDRSTATE_PENDING_INITIALIZATION)
+                rc = kldrDyldModCallInit(pMod);
+        }
+#ifdef KLDRDYLD_STRICT
+        if (!rc)
+            for (iStack = iStackBottom; !rc && iStack < iStackTop; iStack++)
+                KLDRDYLD_ASSERT(g_papStackMods[iStack]->enmState == KLDRSTATE_GOOD);
+#endif
+
+        /*
+         * Complete the load by incrementing the dynamic load count of the
+         * requested module (return handle is already set).
+         */
+        if (!rc)
+        {
+            rc = kldrDyldModDynamicLoad(*ppMod);
+            if (!rc)
+            {
+                kldrDyldStackDropFrame(iStackTop, iStackBottom, rc);
+                kldrDyldModDeref(*ppMod);
+                return rc;
+            }
+        }
+        kldrDyldStackDropFrame(iStackTop, iStackBottom, rc);
+    }
+    else
+    {
+        /* If the reference count is 0 do a quick ref/deref to trigger destruction. */
+        kldrDyldModAddRef(*ppMod);
+        kldrDyldModDeref(*ppMod);
+    }
+
+    /*
+     * We've failed, copy/create error string.
+     */
     return kldrDyldCopyError(rc, pszErr, cchErr);
 }
@@ -543,5 +823,5 @@
 {
     /*
-     * Load all dependant modules.
+     * Load all prerequisite modules.
      */
     PKLDRMOD pCur;
@@ -594,8 +874,132 @@
 #endif
 
+
+/**
+ * Do garbage collection.
+ *
+ * This isn't doing anything unless it's called from the last
+ * load or unload call.
+ */
+static void kldrDyldDoModuleTerminationAndGarabageCollection(void)
+{
+    PKLDRDYLDMOD pMod;
+
+    /*
+     * We don't do anything untill we're got rid of all re-entrant calls.
+     * This will ensure that we get the most optimal termination order and
+     * that we don't unload anything too early.
+     */
+    if (g_cActiveLoadCalls || g_cActiveUnloadCalls || g_fActiveGC)
+        return;
+    g_fActiveGC = 1;
+
+    /*
+     * Release prerequisites to maximize the number of term calls pending.
+     */
+    for (pMod = kLdrDyldHead; pMod; pMod = pMod->Load.pNext);
+    {
+        kldrDyldModAddRef(pMod);
+
+        switch (pMod->enmState)
+        {
+            case KLDRSTATE_GOOD:
+            case KLDRSTATE_PENDING_GC:
+                break;
+
+            case KLDRSTATE_PENDING_INITIALIZATION:
+            case KLDRSTATE_PENDING_TERMINATION:
+                kldrDyldModUnloadPrerequisites(pMod);
+                break;
+
+            default:
+                KLDRDYLD_ASSERT(!"invalid GC state (a)");
+                break;
+        }
+
+        kldrDyldModDeref(pMod);
+    }
+
+    /*
+     * Do termination calls (FIFO order) process new unloads.
+     * The current algorithm here is a bit sluggish, but it ensure correct order.
+     */
+    do
+    {
+        for (pMod = g_pkLdrDyldTermHead; pMod; pMod = pMod->Term.pNext)
+        {
+            int fRestart = 0;
+            kldrDyldModAddRef(pMod);
+
+            switch (pMod->enmState)
+            {
+                case KLDRSTATE_GOOD:
+                case KLDRSTATE_PENDING_GC:
+                    break;
+
+                case KLDRSTATE_PENDING_TERMINATION:
+                    kldrDyldModUnloadPrerequisites(pMod);
+                    kldrDyldModCallTerm(pMod);
+                    fRestart = 1;
+                    break;
+
+                case KLDRSTATE_PENDING_INITIALIZATION:
+                    kldrDyldModUnloadPrerequisites(pMod);
+                    break;
+
+                default:
+                    KLDRDYLD_ASSERT(!"invalid GC state (b)");
+                    break;
+            }
+
+            kldrDyldModDeref(pMod);
+            if (fRestart)
+                break;
+        }
+    } while (pMod);
+
+    /*
+     * Unmap and destroy modules pending for GC.
+     */
+    pMod = kLdrDyldHead;
+    while (pMod)
+    {
+        PKLDRDYLDMOD pNext = pMod->Load.pNext;
+        switch (pMod->enmState)
+        {
+            case KLDRSTATE_PENDING_GC:
+                kldrDyldModAddRef(pMod);
+                KLDRDYLD_ASSERT(pMod->cRefs == 1);
+
+                pMod->enmState = KLDRSTATE_GC;
+                kldrDyldModUnmap(pMod);
+
+                KLDRDYLD_ASSERT(pMod->enmState == KLDRSTATE_PENDING_DESTROY);
+                kldrDyldModDeref(pMod);
+                break;
+
+            /* the only other state that's valid at this point. */
+            case KLDRSTATE_GOOD:
+                break;
+
+            /* all other stats are invalid. */
+            default:
+                KLDRDYLD_ASSERT(!"invalid GC state (c)");
+                break;
+        }
+
+        /* next */
+        pMod = pNext;
+    }
+
+    g_fActiveGC = 0;
+}
+
+
+
 /**
  * Starts loading a new module and its dependencies.
- */
-static void kldrDyldStartLoading(void)
+ * @returns Where the new stack frame starts.
+ */
+static uint32_t kldrDyldStackNewFrame(void)
 {
 #ifdef KLDRDYLD_STRICT
@@ -610,34 +1014,182 @@
     }
 #endif
-}
-
-
-/**
- * Records the loading of the module.
+    return g_cStackMods;
+}
+
+
+/**
+ * Records the module.
  *
  * @return 0 on success, KLDR_ERR_NO_MEMORY if we can't expand the table.
  * @param   pMod        The module to record.
  */
-static int kldrDyldRecord(PKLDRDYLDMOD pMod)
-{
-
-}
-
-
-
-/**
- * Done loading a module and its dependencies.
- *
- * If the load failed, unload all the modules involved.
- * If the load succeeded,
- *
- * @returns rc.
- * @param   rc  The status code.
- */
-static void kldrDyldDoneLoading(int rc)
-{
-
-}
-
+int kldrDyldStackPushModule(PKLDRDYLDMOD pMod)
+{
+    int rc;
+
+    /*
+     * Grow the stack if necessary.
+     */
+    if (g_cStackMods + 1 > g_cStackModsAllocated)
+    {
+        uint32_t cNew = g_cStackModsAllocated ? g_cStackModsAllocated * 2 : 128;
+        void *pvOld = g_papStackMods;
+        void *pvNew = kldrHlpAlloc(cNew * sizeof(g_papStackMods[0]));
+        if (!pvNew)
+            return KLDR_ERR_NO_MEMORY;
+        kLdrHlpMemCopy(pvNew, pvOld, g_cStackMods * sizeof(g_papStackMods[0]));
+        g_papStackMods = (PPKLDRDYLDMOD)pvNew;
+        kldrHlpFree(pvOld);
+    }
+
+    /*
+     * Add a reference and push the module onto the stack.
+     */
+    rc = kldrDyldModAddRef(pMod);
+    if (!rc)
+        g_papStackMods[g_cStackMods++] = pMod;
+    return rc;
+}
+
+
+/**
+ * The frame has been completed.
+ *
+ * @returns Where the frame ends.
+ */
+static int kldrDyldStackFrameCompleted(void)
+{
+    return g_cStackMods;
+}
+
+
+/**
+ * Done with the stack frame, dereference all the module in it.
+ *
+ * @param   iStackTop       The top of the stack frame.
+ * @param   iStackBottom    The bottom of the stack frame.
+ * @param   rc              Used for state verification.
+ */
+static void kldrDyldStackDropFrame(uint32_t iStackTop, uint32_t iStackBottom, int rc)
+{
+    uint32_t iStack;
+    KLDRDYLD_ASSERT(iStackBottom <= g_cStackMods);
+    KLDRDYLD_ASSERT(iStackTop == g_cStackMods);
+
+    /*
+     * First pass, cleanup modules in an obvious 'failed' state so we don't
+     * leave any of the non-reentrant states behind.
+     */
+    for (iStack = iStackBottom; iStack < iStackTop; iStack++)
+    {
+        PKLDRDYLDMOD pMod = g_papStackMods[--iStackTop];
+        switch (pMod->enmState)
+        {
+            /*
+             * Unmap freshly mapped so it can be destroyed.
+             */
+            case KLDRSTATE_MAPPED:
+                KLDRDYLD_ASSERT(rc);
+                kldrDyldModUnmap(pMod);
+                KLDRDYLD_ASSERT(pMod->enmState == KLDRSTATE_PENDING_DESTROY);
+                break;
+
+            /*
+             * Reload is reverted to it's old state.
+             */
+            case KLDRSTATE_RELOADED:
+                KLDRDYLD_ASSERT(rc);
+                pMod->enmState = KLDRSTATE_PENDING_GC;
+                break;
+
+            /*
+             * Unload prerequisites and unmap modules loaded in this frame.
+             */
+            case KLDRSTATE_LOADED_PREREQUISITES:
+            case KLDRSTATE_FIXED_UP: /** @todo fix reload state mess. */
+                KLDRDYLD_ASSERT(rc);
+                kldrDyldModUnloadPrerequisites(pMod);
+                KLDRDYLD_ASSERT(pMod->enmState == KLDRSTATE_PENDING_GC);
+                kldrDyldModUnmap(pMod);
+                KLDRDYLD_ASSERT(pMod->enmState == KLDRSTATE_PENDING_DESTROY);
+                break;
+
+            /*
+             * Ok states.
+             */
+            case KLDRSTATE_INITIALIZING:
+                KLDRDYLD_ASSERT(g_cActiveLoadCalls > 0);
+                break;
+            case KLDRSTATE_TERMINATING:
+                KLDRDYLD_ASSERT(rc);
+                KLDRDYLD_ASSERT(g_fActiveGC);
+                break;
+            case KLDRSTATE_PENDING_TERMINATION:
+            case KLDRSTATE_PENDING_INITIALIZATION:
+            case KLDRSTATE_PENDING_GC:
+            case KLDRSTATE_PENDING_DESTROY:
+                KLDRDYLD_ASSERT(rc);
+                break;
+            case KLDRSTATE_GOOD:
+                break;
+
+            /*
+             * Bad states.
+             */
+            default:
+                KLDRDYLD_ASSERT(!"drop frame bad state (a)");
+                break;
+        }
+    }
+
+    /*
+     * Second pass, release the references to the modules on the stack.
+     */
+    while (iStackTop > iStackBottom)
+    {
+        /*
+         * Pop a module.
+         */
+        PKLDRDYLDMOD pMod = g_papStackMods[--iStackTop];
+        g_cStackMods = iStackTop;
+
+        /*
+         * Validate the state.
+         */
+        switch (pMod->enmState)
+        {
+            /*
+             * Ok states
+             */
+            case KLDRSTATE_INITIALIZING:
+                KLDRDYLD_ASSERT(g_cActiveLoadCalls > 0);
+                break;
+            case KLDRSTATE_TERMINATING:
+                KLDRDYLD_ASSERT(rc);
+                KLDRDYLD_ASSERT(g_fActiveGC);
+                break;
+            case KLDRSTATE_PENDING_INITIALIZATION:
+            case KLDRSTATE_PENDING_TERMINATION:
+            case KLDRSTATE_PENDING_GC:
+            case KLDRSTATE_PENDING_DESTROY:
+                KLDRDYLD_ASSERT(rc);
+                break;
+            case KLDRSTATE_GOOD:
+                break;
+
+            /*
+             * Bad states.
+             */
+            default:
+                KLDRDYLD_ASSERT(!"drop frame bad state (b)");
+                break;
+        }
+
+        /*
+         * Release it.
+         */
+        kldrDyldModDeref(pMod);
+    }
+}
 
 
Index: /trunk/kLdr/kLdrDyldMod.c
===================================================================
--- /trunk/kLdr/kLdrDyldMod.c	(revision 2836)
+++ /trunk/kLdr/kLdrDyldMod.c	(revision 2837)
@@ -35,5 +35,110 @@
 
 
+/*******************************************************************************
+*   Defined Constants And Macros                                               *
+*******************************************************************************/
+/** @def KLDRDYLDMOD_ASSERT
+ * Assert that an expression is true when KLDRDYLD_STRICT is defined.
+ */
+#ifdef KLDRDYLD_STRICT
+# define KLDRDYLDMOD_ASSERT(expr)  kldrHlpAssert(expr)
+#else
+# define KLDRDYLDMOD_ASSERT(expr)  do {} while (0)
+#endif
 
 
 
+
+void kldrDyldModUnloadPrerequisites(PKLDRDYLDMOD pMod)
+{
+
+}
+
+
+void kldrDyldModDeref(PKLDRDYLDMOD pMod)
+{
+    /* validate input */
+    KLDRDYLDMOD_ASSERT(pMod->enmState > KLDRSTATE_INVALID && pMod->enmState < KLDRSTATE_END);
+    KLDRDYLDMOD_ASSERT(pMod->cRefs > 0);
+    KLDRDYLDMOD_ASSERT(pMod->cRefs >= pMod->cDepRefs + pMod->cDynRefs);
+
+    /* decrement. */
+    if (pMod->cRefs > 0)
+        pMod->cRefs--;
+
+    /*
+     * Drop prerequisites for stats that implies that no recursion can have taken place yet.
+     * This ASSUMES that we're only dereferencing modules when an operation completes.
+     * (This is *required* for the reloaded state.)
+     */
+    switch (pMod->enmState)
+    {
+        case KLDRSTATE_MAPPED:
+        case KLDRSTATE_LOADED_PREREQUISITES:
+        case KLDRSTATE_FIXED_UP:
+        case KLDRSTATE_RELOADED:
+            kldrDyldModUnloadPrerequisites(pMod);
+            pMod->enmState = KLDRSTATE_PENDING_GC;
+            break;
+
+        case KLDRSTATE_PENDING_INITIALIZATION:
+        case KLDRSTATE_INITIALIZING:
+        case KLDRSTATE_GOOD:
+        case KLDRSTATE_PENDING_TERMINATION:
+        case KLDRSTATE_TERMINATING:
+        case KLDRSTATE_PENDING_GC:
+        case KLDRSTATE_GC:
+        case KLDRSTATE_PENDING_DESTROY:
+            break;
+
+        default:
+            KLDRDYLDMOD_ASSERT(!"Invalid deref state");
+            break;
+    }
+
+    /*
+     * Also drop prerequisites if noone is referencing the module.
+     */
+    if (!pMod->cDepRefs && !pMod->cDynRefs)
+    {
+        switch (pMod->enmState)
+        {
+            case KLDRSTATE_MAPPED:
+            case KLDRSTATE_LOADED_PREREQUISITES:
+            case KLDRSTATE_FIXED_UP:
+            case KLDRSTATE_RELOADED:
+                /* already dropped. */
+                break;
+
+            case KLDRSTATE_PENDING_INITIALIZATION:
+                kldrDyldModUnloadPrerequisites(pMod);
+                pMod->enmState = KLDRSTATE_PENDING_GC;
+                break;
+
+            case KLDRSTATE_GOOD:
+                pMod->enmState = KLDRSTATE_PENDING_TERMINATION;
+            case KLDRSTATE_PENDING_TERMINATION:
+            case KLDRSTATE_PENDING_GC:
+                kldrDyldModUnloadPrerequisites(pMod);
+                break;
+
+            case KLDRSTATE_TERMINATING:
+            case KLDRSTATE_GC:
+            case KLDRSTATE_PENDING_DESTROY:
+                break;
+
+            default:
+                KLDRDYLDMOD_ASSERT(!"Invalid deref state (b)");
+                break;
+        }
+    }
+
+    /*
+     * If there are no references whatsoever now and the module
+     * is pending destruction, destroy it.
+     */
+    if (    !pMod->cRefs
+        &&  (   pMod->enmState == KLDRSTATE_PENDING_DESTROY
+             || pMod->enmState == KLDRSTATE_GC))
+        kldrDyldModDestroy(pMod);
+}
Index: /trunk/kLdr/kLdrInternal.h
===================================================================
--- /trunk/kLdr/kLdrInternal.h	(revision 2836)
+++ /trunk/kLdr/kLdrInternal.h	(revision 2837)
@@ -77,14 +77,20 @@
     /** The module been mapped.
      * Prev state: OPEN
-     * Next state: LOADED_DEPS, DESTROYED
+     * Next state: LOADED_PREREQUISITES, DESTROYED
      */
     KLDRSTATE_MAPPED,
-    /** The immediate dependencies has been loaded.
-     * Prev state: MAPPED
+    /** The module has been reloaded and needs to be fixed up again.
+     * (The loader can still be in a re-entrant mode.)
+     * Prev state: PENDING_GC
+     * Next state: LOADED_PREREQUISITES, PENDING_GC
+     */
+    KLDRSTATE_RELOADED,
+    /** The immediate prerequisites have been loaded.
+     * Prev state: MAPPED, RELOADED
      * Next state: FIXED_UP, DESTROYED
      */
-    KLDRSTATE_LOADED_DEPS,
+    KLDRSTATE_LOADED_PREREQUISITES,
     /** Fixups has been applied.
-     * Prev state: LOADED_DEPS
+     * Prev state: LOADED_PREREQUISITES
      * Next state: PENDING_INIT, DESTROYED
      */
@@ -124,21 +130,19 @@
      * (The loader can still be in a re-entrant mode.)
      * Prev state: TERMINATING, INITIALIZING, PENDING_INITIALIZATION
-     * Next state: GC, RELOADING
+     * Next state: GC, RELOADED
      */
     KLDRSTATE_PENDING_GC,
     /** Being garbage collected.
-     * (The loader can still be in a re-entrant mode.)
      * Prev state: PENDING_GC
+     * Next state: PENDING_DESTROY, DESTROYED
+     */
+    KLDRSTATE_GC,
+    /** The module has be unlinked, but there are still stack references to it.
+     * Prev state: GC
      * Next state: DESTROYED
      */
-    KLDRSTATE_GC,
-    /** The module is being reloaded after having been scheduled for termination or/and GC.
-     * (The loader can still be in a re-entrant mode.)
-     * Prev state: PENDING_GC
-     * Next state: PENDING_INITIALIZATION
-     */
-    KLDRSTATE_RELOADING,
+    KLDRSTATE_PENDING_DESTROY,
     /** The module has been destroyed and is no longer valid.
-     * Prev state: GC
+     * Prev state: GC, PENDING_DESTROY
      */
     KLDRSTATE_DESTROYED,
@@ -163,13 +167,10 @@
     /** The module handle. */
     HKLDRMOD            hMod;
-    /** The number of references. */
+    /** The total number of references. */
     uint32_t            cRefs;
-    /** The number of dynamic references. */
+    /** The number of dependency references. */
+    uint32_t            cDepRefs;
+    /** The number of dynamic load references. */
     uint32_t            cDynRefs;
-    /** The number of dynamic load operations in progress.
-     * This is used to reject anyone trying to unload a module before the load has
-     * been completed. An alternative to this would be to not add the cDynRefs until
-     * the load operation has completed... */
-    uint32_t            cDynRefsInProgress;
     /** Set if this is the executable module.
      * When clear, the module is a shared object or relocatable object. */
@@ -180,5 +181,9 @@
     uint32_t            fBindable : 1;
     /** Reserved for future use. */
-    uint32_t            fReserved : 29;
+    uint32_t            fReserved : 28;
+    /** Already checked dependencies.
+     * This is flag used when resolving module dependencies during a load, it
+     * deals with modules in the KLDRSTATE_PENDING_INITIALIZATION state. */
+    uint32_t            fAlreadySeen : 1;
     /** The load list linkage. */
     struct
@@ -233,6 +238,8 @@
 int kldrDyldModCreate(PKLDRRDR pRdr, PPKLDRDYLDMOD ppMod);
 int kldrDyldModDestroy(PKLDRDYLDMOD pMod);
-int kldrDyldModAddDep(PKLDRDYLDMOD pMod, PKLDRDYLDMOD pModDep);
-int kldrDyldModRemoveDep(PKLDRDYLDMOD pMod, PKLDRDYLDMOD pModDep);
+int kldrDyldModAddRef(PKLDRDYLDMOD pMod);
+void kldrDyldModDeref(PKLDRDYLDMOD pMod);
+int kldrDyldModAddDep(PKLDRDYLDMOD pMod, PKLDRDYLDMOD pDep);
+void kldrDyldModRemoveDep(PKLDRDYLDMOD pMod, PKLDRDYLDMOD pDep);
 int kldrDyldModDynamicLoad(PKLDRDYLDMOD pMod);
 int kldrDyldModDynamicUnload(PKLDRDYLDMOD pMod);
@@ -245,8 +252,12 @@
 int kldrDyldModMap(PKLDRDYLDMOD pMod);
 int kldrDyldModUnmap(PKLDRDYLDMOD pMod);
-int kldrDyldModLoadDependencies(PKLDRDYLDMOD pMod);
+int kldrDyldModLoadPrerequisites(PKLDRDYLDMOD pMod, const char *pszName, const char *pszDefPrefix, const char *pszDefSuffix,
+                                 KLDRDYLDSEARCH enmSearch, unsigned fFlags);
+int kldrDyldModCheckPrerequisites(PKLDRDYLDMOD pMod);
+void kldrDyldModUnloadPrerequisites(PKLDRDYLDMOD pMod);
 int kldrDyldModFixup(PKLDRDYLDMOD pMod);
 int kldrDyldModCallInit(PKLDRDYLDMOD pMod);
-int kldrDyldModCallTerm(PKLDRDYLDMOD pMod);
+void kldrDyldModCallTerm(PKLDRDYLDMOD pMod);
+int kldrDyldModReload(PKLDRDYLDMOD pMod);
 int kldrDyldModAttachThread(PKLDRDYLDMOD pMod);
 int kldrDyldModDetachThread(PKLDRDYLDMOD pMod);
