Changeset 2842


Ignore:
Timestamp:
Oct 30, 2006, 1:49:15 AM (19 years ago)
Author:
bird
Message:

toplevel load api code is done.

Location:
trunk/kLdr
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/kLdr/kLdr.h

    r2840 r2842  
    545545/** Returns ALL kinds of symbols. The default is to only return public/exported symbols. */
    546546#define KLDRMOD_ENUM_SYMBOL_FLAGS_ALL       0x00000001
     547/** Do a recursive initialization calls instead of defering them to the outermost call. */
     548#define KLDRDYLD_LOAD_FLAGS_RECURSIVE_INIT  0x00000002
    547549/** @} */
    548550
     
    734736
    735737/** Invalid parameter to a kLdr API. */
    736 #define KLDR_ERR_INVALID_PARAMETER      (KLDR_ERR_BASE + 32)
     738#define KLDR_ERR_INVALID_PARAMETER                          (KLDR_ERR_BASE + 32)
    737739/** Invalid handle parameter to a kLdr API. */
    738 #define KLDR_ERR_INVALID_HANDLE         (KLDR_ERR_BASE + 33)
     740#define KLDR_ERR_INVALID_HANDLE                             (KLDR_ERR_BASE + 33)
     741/** The module wasn't loaded dynamically. */
     742#define KLDR_ERR_NOT_LOADED_DYNAMICALLY                     (KLDR_ERR_BASE + 34)
    739743/** The module wasn't found. */
    740 #define KLDR_ERR_MODULE_NOT_FOUND                   (KLDR_ERR_BASE + 34)
     744#define KLDR_ERR_MODULE_NOT_FOUND                           (KLDR_ERR_BASE + 35)
    741745/** A prerequisit module wasn't found. */
    742 #define KLDR_ERR_PREREQUISITE_MODULE_NOT_FOUND      (KLDR_ERR_BASE + 35)
     746#define KLDR_ERR_PREREQUISITE_MODULE_NOT_FOUND              (KLDR_ERR_BASE + 36)
    743747/** The module is being terminated and can therefore not be loaded. */
    744 #define KLDR_ERR_MODULE_TERMINATING                 (KLDR_ERR_BASE + 36)
     748#define KLDR_ERR_MODULE_TERMINATING                         (KLDR_ERR_BASE + 37)
    745749/** A prerequisit module is being terminated and can therefore not be loaded. */
    746 #define KLDR_ERR_PREREQUISITE_MODULE_TERMINATING    (KLDR_ERR_BASE + 37)
    747 /** An allocation failed. */
    748 #define KLDR_ERR_NO_MEMORY                          (KLDR_ERR_BASE + 38)
     750#define KLDR_ERR_PREREQUISITE_MODULE_TERMINATING            (KLDR_ERR_BASE + 38)
     751/** The module initialization failed. */
     752#define KLDR_ERR_MODULE_INIT_FAILED                         (KLDR_ERR_BASE + 39)
     753/** The initialization of a prerequisite module failed. */
     754#define KLDR_ERR_PREREQUISITE_MODULE_INIT_FAILED            (KLDR_ERR_BASE + 40)
     755/** The module has already failed initialization and can't be attempted reloaded until
     756 * after we've finished garbage collection. */
     757#define KLDR_ERR_MODULE_INIT_FAILED_ALREADY                 (KLDR_ERR_BASE + 41)
     758/** A prerequisite module has already failed initialization and can't be attempted
     759 * reloaded until after we've finished garbage collection. */
     760#define KLDR_ERR_PREREQUISITE_MODULE_INIT_FAILED_ALREADY    (KLDR_ERR_BASE + 42)
     761/** Prerequisite recursed too deeply. */
     762#define KLDR_ERR_PREREQUISITE_RECURSED_TOO_DEEPLY           (KLDR_ERR_BASE + 43)
    749763
    750764
    751765/** Encountered a bad fixup. */
    752 #define KLDR_ERR_BAD_FIXUP              (KLDR_ERR_BASE + 48)
     766#define KLDR_ERR_BAD_FIXUP                                  (KLDR_ERR_BASE + 48)
     767
     768/** A memory allocation failed. */
     769#define KLDR_ERR_NO_MEMORY                                  (KLDR_ERR_BASE + 64)
    753770
    754771/** @} */
  • trunk/kLdr/kLdrDyld.c

    r2837 r2842  
    4949# define KLDRDYLD_ASSERT(expr)  do {} while (0)
    5050#endif
     51
     52
     53/*******************************************************************************
     54*   Structures and Typedefs                                                    *
     55*******************************************************************************/
    5156
    5257
     
    6065 * (This is exported, so no prefix.) */
    6166PKLDRDYLDMOD    kLdrDyldTail = NULL;
     67/** Pointer to the head module of the initialization list.
     68 * The outermost load call will pop elements from this list in LIFO order (i.e.
     69 * from the tail). The list is only used during non-recursive initialization
     70 * and may therefore share the pNext/pPrev members with the termination list
     71 * since we don't push a module onto the termination list untill it has been
     72 * successfully initialized. */
     73PKLDRDYLDMOD    g_pkLdrDyldInitHead;
     74/** Pointer to the tail module of the initalization list. */
     75PKLDRDYLDMOD    g_pkLdrDyldInitTail;
    6276/** Pointer to the head module of the termination order list. */
    6377PKLDRDYLDMOD    g_pkLdrDyldTermHead;
     
    98112/** Number of active unload calls. */
    99113static uint32_t         g_cActiveUnloadCalls;
     114/** Total number of load calls. */
     115static uint32_t         g_cTotalLoadCalls;
     116/** Total mumber of unload calls. */
     117static uint32_t         g_cTotalUnloadCalls;
    100118/** Boolean flag indicating that GC is active. */
    101119static uint32_t         g_fActiveGC;
    102 
    103120
    104121/** The global error buffer. */
     
    115132*   Internal Functions                                                         *
    116133*******************************************************************************/
     134/** @name API worker routines.
     135 * @internal
     136 * @{ */
    117137static int kldrDyldDoLoad(const char *pszDll, const char *pszDefPrefix, const char *pszDefSuffix, KLDRDYLDSEARCH enmSearch,
    118138                          unsigned fFlags, PPKLDRDYLDMOD ppMod, char *pszErr, size_t cchErr);
     139static int kldrDyldDoLoadPrerequisites(PKLDRDYLDMOD pMod, const char *pszDefPrefix, const char *pszDefSuffix,
     140                                       KLDRDYLDSEARCH enmSearch, unsigned fFlags);
    119141static int kldrDyldDoUnload(PKLDRDYLDMOD pMod);
    120142static int kldrDyldDoFindByName(const char *pszDll, const char *pszDefPrefix, const char *pszDefSuffix, KLDRDYLDSEARCH enmSearch,
     
    124146static int kldrDyldDoGetFilename(PKLDRDYLDMOD pMod, char *pszFilename, size_t cchFilename);
    125147static int kldrDyldDoQuerySymbol(PKLDRDYLDMOD pMod, uint32_t uSymbolOrdinal, const char *pszSymbolName, uintptr_t *pValue, uint32_t *pfKind);
    126 
    127 static void     kldrDyldDoModuleTerminationAndGarabageCollection(void);
    128 
    129 static uint32_t kldrDyldStackNewFrame(void);
    130 int     kldrDyldStackPushModule(PKLDRDYLDMOD pMod);
    131 static int      kldrDyldStackFrameCompleted(void);
    132 static void     kldrDyldStackDropFrame(uint32_t iStackTop, uint32_t iStackBottom, int rc);
    133 
    134 static int      kldrDyldCopyError(int rc, char *pszErr, size_t cchErr);
     148/** @} */
     149
     150/** @name Misc load/unload workers
     151 * @internal
     152 * @{
     153 */
     154static void         kldrDyldDoModuleTerminationAndGarabageCollection(void);
     155/** @} */
     156
     157/** @name The load stack.
     158 * @internal
     159 * @{ */
     160static uint32_t     kldrDyldStackNewFrame(PKLDRDYLDMOD pMod);
     161static int          kldrDyldStackAddModule(PKLDRDYLDMOD pMod);
     162static int          kldrDyldStackFrameCompleted(void);
     163static void         kldrDyldStackDropFrame(uint32_t iLoad1st, uint32_t iLoadEnd, int rc);
     164/** @} */
     165
     166static int          kldrDyldCopyError(int rc, char *pszErr, size_t cchErr);
    135167
    136168
     
    192224    {
    193225        PKLDRDYLDMOD pMod = NULL;
     226        g_cTotalLoadCalls++;
    194227        g_cActiveLoadCalls++;
    195228        rc = kldrDyldDoLoad(pszDll, pszDefPrefix, pszDefSuffix, enmSearch, fFlags, phMod, pszErr, cchErr);
     
    220253    if (!rc)
    221254    {
     255        g_cTotalUnloadCalls++;
    222256        g_cActiveUnloadCalls++;
    223257        rc = kldrDyldDoUnload(hMod);
     
    404438
    405439/**
     440 * Worker for kLdrDyldLoad() and helper for kLdrDyldLoadExe().
     441 * @internal
     442 */
     443static int kldrDyldDoLoad(const char *pszDll, const char *pszDefPrefix, const char *pszDefSuffix, KLDRDYLDSEARCH enmSearch,
     444                          unsigned fFlags, PPKLDRDYLDMOD ppMod, char *pszErr, size_t cchErr)
     445{
     446    int rc;
     447
     448    /*
     449     * Try find the module among the ones that's already loaded.
     450     */
     451    rc = kldrDyldFindExistingModule(pszDll, pszDefPrefix, pszDefSuffix, enmSearch, fFlags, ppMod);
     452    if (!rc)
     453    {
     454        switch ((*ppMod)->enmState)
     455        {
     456            /*
     457             * Prerequisites are ok, so nothing to do really.
     458             */
     459            case KLDRSTATE_GOOD:
     460            case KLDRSTATE_INITIALIZING:
     461                return kldrDyldModDynamicLoad(*ppMod);
     462
     463            /*
     464             * The module can't be loaded because it failed to initialize.
     465             */
     466            case KLDRSTATE_INITIALIZATION_FAILED:
     467                return KLDR_ERR_MODULE_INIT_FAILED_ALREADY;
     468
     469            /*
     470             * Prerequisites needs loading / reattaching and the module
     471             * (may depending on fFlags) needs to be initialized.
     472             */
     473            case KLDRSTATE_PENDING_INITIALIZATION:
     474                break;
     475
     476            /*
     477             * Prerequisites needs to be loaded again
     478             */
     479            case KLDRSTATE_PENDING_TERMINATION:
     480                break;
     481
     482            /*
     483             * The module has been terminated so it need to be reloaded, have it's
     484             * prereqs loaded, fixed up and initialized before we can use it again.
     485             */
     486            case KLDRSTATE_PENDING_GC:
     487                rc = kldrDyldModReload(*ppMod);
     488                if (rc)
     489                    return kldrDyldCopyError(rc, pszErr, cchErr);
     490                break;
     491
     492            /*
     493             * Forget it, we don't know how to deal with re-initialization here.
     494             */
     495            case KLDRSTATE_TERMINATING:
     496                KLDRDYLD_ASSERT(!"KLDR_ERR_MODULE_TERMINATING");
     497                return KLDR_ERR_MODULE_TERMINATING;
     498
     499            /*
     500             * Invalid state.
     501             */
     502            default:
     503                KLDRDYLD_ASSERT(!"invalid state");
     504                break;
     505        }
     506    }
     507    else
     508    {
     509        /*
     510         * We'll have to load it from file.
     511         */
     512        rc = kldrDyldFindNewModule(pszDll, pszDefPrefix, pszDefSuffix, enmSearch, fFlags, ppMod);
     513        if (rc)
     514            return kldrDyldCopyError(rc, pszErr, cchErr);
     515        rc = kldrDyldModMap(*ppMod);
     516    }
     517
     518    if (!rc)
     519    {
     520        /*
     521         * Load prerequisites.
     522         */
     523        uint32_t i;
     524        uint32_t iLoadEnd;
     525        uint32_t iLoad1st = kldrDyldStackNewFrame(*ppMod);
     526        rc = kldrDyldDoLoadPrerequisites(*ppMod, pszDefPrefix, pszDefSuffix, enmSearch, fFlags);
     527        iLoadEnd = kldrDyldStackFrameCompleted();
     528
     529        /*
     530         * Apply fixups.
     531         */
     532        for (i = iLoad1st; !rc && i < iLoadEnd; i++)
     533        {
     534            PKLDRDYLDMOD pMod = g_papStackMods[i];
     535            if (    pMod->enmState == KLDRSTATE_LOADED_PREREQUISITES
     536                ||  pMod->enmState == KLDRSTATE_RELOADED_LOADED_PREREQUISITES)
     537                rc = kldrDyldModFixup(pMod);
     538        }
     539
     540        /*
     541         * Advance fixed up module onto initialization.
     542         */
     543        for (i = iLoad1st; !rc && i < iLoadEnd; i++)
     544        {
     545            PKLDRDYLDMOD pMod = g_papStackMods[i];
     546            if (    pMod->enmState == KLDRSTATE_FIXED_UP
     547                ||  pMod->enmState == KLDRSTATE_RELOADED_FIXED_UP)
     548                pMod->enmState = KLDRSTATE_PENDING_INITIALIZATION;
     549            KLDRDYLD_ASSERT(    pMod->enmState == KLDRSTATE_PENDING_INITIALIZATION
     550                            ||  pMod->enmState == KLDRSTATE_GOOD);
     551        }
     552
     553        /*
     554         * Call the initializers if we're loading in recursive mode or
     555         * if we're the outermost load call.
     556         */
     557        if (fFlags & KLDRDYLD_LOAD_FLAGS_RECURSIVE_INIT)
     558        {
     559            for (i = iLoad1st; !rc && i < iLoadEnd; i++)
     560            {
     561                PKLDRDYLDMOD pMod = g_papStackMods[i];
     562                if (pMod->enmState == KLDRSTATE_PENDING_INITIALIZATION)
     563                    rc = kldrDyldModCallInit(pMod);
     564                else if (pMod->enmState == KLDRSTATE_INITIALIZATION_FAILED)
     565                    rc = KLDR_ERR_PREREQUISITE_MODULE_INIT_FAILED_ALREADY;
     566                else
     567                    KLDRDYLD_ASSERT(g_papStackMods[i]->enmState == KLDRSTATE_GOOD);
     568            }
     569#ifdef KLDRDYLD_STRICT
     570            for (i = iLoad1st; !rc && i < iLoadEnd; i++)
     571                KLDRDYLD_ASSERT(g_papStackMods[i]->enmState == KLDRSTATE_GOOD);
     572#endif
     573        }
     574        else if (g_cActiveLoadCalls <= 1)
     575        {
     576            while (!rc && g_pkLdrDyldInitHead)
     577            {
     578                PKLDRDYLDMOD pMod = g_pkLdrDyldInitHead;
     579                g_pkLdrDyldInitHead = pMod->InitTerm.pNext;
     580                if (pMod->InitTerm.pNext)
     581                    pMod->InitTerm.pNext->InitTerm.pPrev = NULL;
     582                rc = kldrDyldModCallInit(pMod);
     583            }
     584        }
     585
     586        /*
     587         * Complete the load by incrementing the dynamic load count of the
     588         * requested module (return handle is already set).
     589         */
     590        if (!rc)
     591        {
     592            rc = kldrDyldModDynamicLoad(*ppMod);
     593            if (!rc)
     594            {
     595                kldrDyldStackDropFrame(iLoad1st, iLoadEnd, rc);
     596                kldrDyldModDeref(*ppMod);
     597                return rc;
     598            }
     599        }
     600        kldrDyldStackDropFrame(iLoad1st, iLoadEnd, rc);
     601    }
     602    else
     603    {
     604        /* If the reference count is 0 do a quick ref/deref to trigger destruction. */
     605        kldrDyldModAddRef(*ppMod);
     606        kldrDyldModDeref(*ppMod);
     607    }
     608
     609    /*
     610     * We've failed, copy/create error string.
     611     */
     612    return kldrDyldCopyError(rc, pszErr, cchErr);
     613}
     614
     615
     616/**
     617 * kldrDyldDoLoad() helper which will load prerequisites and
     618 * build the initialization array / list.
     619 *
     620 * @returns 0 on success, non-zero error code on failure.
     621 * @param   pMod            The module to start at.
     622 * @param   pszDefPrefix    Prefix to use when searching.
     623 * @param   pszDefSuffix    Suffix to use when searching.
     624 * @param   enmSearch       Method to use when locating the module and any modules it may depend on.
     625 * @param   fFlags          Flags, a combintation of the KLDRYDLD_LOAD_FLAGS_* \#defines.
     626 */
     627static int kldrDyldDoLoadPrerequisites(PKLDRDYLDMOD pMod, const char *pszDefPrefix, const char *pszDefSuffix,
     628                                       KLDRDYLDSEARCH enmSearch, unsigned fFlags)
     629{
     630    static struct
     631    {
     632        /** The module. */
     633        PKLDRDYLDMOD    pMod;
     634        /** The number of prerequisite modules left to process.
     635         * This starts at ~0U to inidicate that we need to load/check prerequisistes. */
     636        unsigned        cLeft;
     637    }               s_aEntries[64];
     638    unsigned        cEntries;
     639    int             rc = 0;
     640
     641    /* push the first entry. */
     642    s_aEntries[0].pMod = pMod;
     643    s_aEntries[0].cLeft = ~0U;
     644    cEntries = 1;
     645
     646    /*
     647     * The recursion loop.
     648     */
     649    while (!rc && cEntries > 0)
     650    {
     651        const unsigned i = cEntries - 1;
     652        pMod = s_aEntries[i].pMod;
     653        if (s_aEntries[i].cLeft == ~0U)
     654        {
     655            /*
     656             * Load prerequisite modules.
     657             */
     658            switch (pMod->enmState)
     659            {
     660                /*
     661                 * Load immediate prerequisite modules and push the ones needing
     662                 * attention onto the stack.
     663                 */
     664                case KLDRSTATE_MAPPED:
     665                case KLDRSTATE_RELOADED:
     666                case KLDRSTATE_PENDING_TERMINATION:
     667                    rc = kldrDyldModLoadPrerequisites(pMod, pszDefPrefix, pszDefSuffix, enmSearch, fFlags);
     668                    KLDRDYLD_ASSERT(    pMod->enmState == KLDRSTATE_GOOD
     669                                    ||  pMod->enmState == KLDRSTATE_RELOADED_LOADED_PREREQUISITES
     670                                    ||  pMod->enmState == KLDRSTATE_LOADED_PREREQUISITES
     671                                    ||  rc);
     672                    if (!rc)
     673                        s_aEntries[i].cLeft = pMod->cPrereqs;
     674                    break;
     675
     676                /*
     677                 * Check its prerequisite modules the first time around.
     678                 */
     679                case KLDRSTATE_PENDING_INITIALIZATION:
     680                    if (pMod->fAlreadySeen)
     681                        break;
     682                    pMod->fAlreadySeen = 1;
     683                    s_aEntries[i].cLeft = pMod->cPrereqs;
     684                    break;
     685
     686                /*
     687                 * These are ok.
     688                 */
     689                case KLDRSTATE_LOADED_PREREQUISITES:
     690                case KLDRSTATE_RELOADED_LOADED_PREREQUISITES:
     691                case KLDRSTATE_INITIALIZING:
     692                case KLDRSTATE_GOOD:
     693                    s_aEntries[i].cLeft = 0;
     694                    break;
     695
     696                /*
     697                 * All other stats are invalid.
     698                 */
     699                default:
     700                    KLDRDYLD_ASSERT(!"invalid state");
     701                    break;
     702            }
     703        }
     704        else if (s_aEntries[i].cLeft > 0)
     705        {
     706            /*
     707             * Recurse down into the next prereq.
     708             */
     709            KLDRDYLD_ASSERT(s_aEntries[i].cLeft <= pMod->cPrereqs);
     710            if (cEntries < sizeof(s_aEntries) / sizeof(s_aEntries[0]))
     711            {
     712                s_aEntries[cEntries++].pMod = pMod->papPrereqs[pMod->cPrereqs - s_aEntries[i].cLeft];
     713                s_aEntries[i].cLeft--;
     714            }
     715            else
     716                rc = KLDR_ERR_PREREQUISITE_RECURSED_TOO_DEEPLY;
     717        }
     718        else
     719        {
     720            /*
     721             * We're done with this module, record it for init/cleanup.
     722             */
     723            cEntries--;
     724            if (pMod->enmState != KLDRSTATE_GOOD)
     725            {
     726                kldrDyldStackAddModule(pMod);
     727                if  (   !(fFlags & KLDRDYLD_LOAD_FLAGS_RECURSIVE_INIT)
     728                     && !pMod->fInitList)
     729                {
     730                    pMod->fInitList = 1;
     731                    pMod->InitTerm.pNext = NULL;
     732                    pMod->InitTerm.pPrev = g_pkLdrDyldInitTail;
     733                    if (g_pkLdrDyldInitTail)
     734                        g_pkLdrDyldInitTail->InitTerm.pNext = pMod;
     735                    else
     736                        g_pkLdrDyldInitHead = pMod;
     737                    g_pkLdrDyldInitTail = pMod;
     738                }
     739            }
     740        }
     741    }
     742
     743    return rc;
     744}
     745
     746
     747/**
    406748 * Gets prerequisite module.
    407749 *
     
    421763                            unsigned fFlags, PKLDRDYLDMOD pDep, PPKLDRDYLDMOD ppMod)
    422764{
    423     int rc;
     765    int             rc;
     766    PKLDRDYLDMOD    pMod;
    424767
    425768    *ppMod = NULL;
     
    427770    /*
    428771     * Try find the module among the ones that's already loaded.
    429      */
    430     rc = kldrDyldFindExistingModule(pszDll, pszDefPrefix, pszDefSuffix, enmSearch, fFlags, ppMod);
     772     *
     773     * This is very similar to the kldrDyldDoLoad code, except it has to deal with
     774     * a couple of additional states and occurs only during prerequisite loading
     775     * and the action taken is a little bit different.
     776     */
     777    rc = kldrDyldFindExistingModule(pszDll, pszDefPrefix, pszDefSuffix, enmSearch, fFlags, &pMod);
    431778    if (!rc)
    432779    {
    433         /*
    434          * See if the module should go on the stack and if it needs
    435          * some work before that.
    436          */
    437         switch ((*ppMod)->enmState)
    438         {
    439             /*
    440              * The module is good, just add the dependency.
    441              */
     780        switch (pMod->enmState)
     781        {
     782            /*
     783             * These are good.
     784             */
     785            case KLDRSTATE_MAPPED:
     786            case KLDRSTATE_RELOADED:
     787            case KLDRSTATE_LOADED_PREREQUISITES:
     788            case KLDRSTATE_RELOADED_LOADED_PREREQUISITES:
     789            case KLDRSTATE_PENDING_INITIALIZATION:
     790            case KLDRSTATE_INITIALIZING:
    442791            case KLDRSTATE_GOOD:
    443             case KLDRSTATE_INITIALIZING:
    444                 return kldrDyldModAddDep(*ppMod, pDep);
    445 
    446             /*
    447              * Prerequisites needs checking.
    448              */
    449             case KLDRSTATE_PENDING_INITIALIZATION:
    450                 (*ppMod)->fAlreadySeen = 0;
    451792            case KLDRSTATE_PENDING_TERMINATION:
    452793                break;
     
    457798             */
    458799            case KLDRSTATE_PENDING_GC:
    459                 rc = kldrDyldModReload(*ppMod);
    460                 if (rc)
    461                     return rc;
    462                 break;
    463 
    464             /*
    465              * It's just been loaded or reloaded in this session, we will push it
    466              * onto the stack even so to get a consisten init order with the other
    467              * states.
    468              */
    469             case KLDRSTATE_MAPPED:
    470             case KLDRSTATE_RELOADED:
    471                 break;
    472 
    473             /*
    474              * Forget it, we don't know how to deal with re-initialization here.
     800                rc = kldrDyldModReload(pMod);
     801                break;
     802
     803            /*
     804             * The module can't be loaded because it failed to initialize already.
     805             */
     806            case KLDRSTATE_INITIALIZATION_FAILED:
     807                rc = KLDR_ERR_PREREQUISITE_MODULE_INIT_FAILED;
     808                break;
     809
     810            /*
     811             * Forget it, no idea how to deal with re-initialization.
    475812             */
    476813            case KLDRSTATE_TERMINATING:
    477                 KLDRDYLD_ASSERT(!"KLDR_ERR_PREREQUISITE_MODULE_TERMINATING");
    478814                return KLDR_ERR_PREREQUISITE_MODULE_TERMINATING;
    479815
     
    493829        rc = kldrDyldFindNewModule(pszDll, pszDefPrefix, pszDefSuffix, enmSearch, fFlags, ppMod);
    494830        if (!rc)
    495             rc = kldrDyldModMap(*ppMod);
    496     }
    497 
    498     /*
    499      * Push it onto the stack and add the dependency.
     831            rc = kldrDyldModMap(pMod);
     832    }
     833
     834    /*
     835     * On success add dependency.
    500836     */
    501837    if (!rc)
    502         rc = kldrDyldStackPushModule(*ppMod);
     838    {
     839        rc = kldrDyldModAddDep(pMod, pDep);
     840        if (!rc)
     841            *ppMod = pMod;
     842    }
     843    return rc;
     844}
     845
     846
     847/**
     848 * Starts a new load stack frame.
     849 *
     850 * @returns Where the new stack frame starts.
     851 * @param   pLoadMod        The module being loaded (only used for asserting).
     852 */
     853static uint32_t kldrDyldStackNewFrame(PKLDRDYLDMOD pLoadMod)
     854{
     855    /*
     856     * Clear the fAlreadySeen flags.
     857     */
     858    PKLDRDYLDMOD pMod = kLdrDyldHead;
     859    while (pMod)
     860    {
     861        pMod->fAlreadySeen = 0;
     862
     863#ifdef KLDRDYLD_ASSERT
     864        switch (pMod->enmState)
     865        {
     866            case KLDRSTATE_MAPPED:
     867            case KLDRSTATE_RELOADED:
     868                /* only the just loaded module can be in this state. */
     869                KLDRDYLD_ASSERT(pMod == pLoadMod);
     870                break;
     871
     872            case KLDRSTATE_PENDING_INITIALIZATION:
     873            case KLDRSTATE_INITIALIZING:
     874            case KLDRSTATE_PENDING_TERMINATION:
     875            case KLDRSTATE_PENDING_GC:
     876            case KLDRSTATE_TERMINATING:
     877            case KLDRSTATE_INITIALIZATION_FAILED:
     878            case KLDRSTATE_PENDING_DESTROY:
     879                /* requires recursion. */
     880                KLDRDYLD_ASSERT(g_cActiveLoadCalls + g_cActiveLoadCalls + g_fActiveGC > 1);
     881                break;
     882
     883            case KLDRSTATE_GOOD:
     884                /* requires nothing. */
     885                break;
     886
     887            default:
     888                KLDRDYLD_ASSERT(!"Invalid state");
     889                break;
     890        }
     891#endif
     892
     893        /* next */
     894        pMod = pMod->Load.pNext;
     895    }
     896    return g_cStackMods;
     897}
     898
     899
     900/**
     901 * Records the module.
     902 *
     903 * @return 0 on success, KLDR_ERR_NO_MEMORY if we can't expand the table.
     904 * @param   pMod        The module to record.
     905 */
     906static int kldrDyldStackAddModule(PKLDRDYLDMOD pMod)
     907{
     908    int rc;
     909
     910    /*
     911     * Grow the stack if necessary.
     912     */
     913    if (g_cStackMods + 1 > g_cStackModsAllocated)
     914    {
     915        uint32_t cNew = g_cStackModsAllocated ? g_cStackModsAllocated * 2 : 128;
     916        void *pvOld = g_papStackMods;
     917        void *pvNew = kldrHlpAlloc(cNew * sizeof(g_papStackMods[0]));
     918        if (!pvNew)
     919            return KLDR_ERR_NO_MEMORY;
     920        kLdrHlpMemCopy(pvNew, pvOld, g_cStackMods * sizeof(g_papStackMods[0]));
     921        g_papStackMods = (PPKLDRDYLDMOD)pvNew;
     922        kldrHlpFree(pvOld);
     923    }
     924
     925    /*
     926     * Add a reference and push the module onto the stack.
     927     */
     928    rc = kldrDyldModAddRef(pMod);
    503929    if (!rc)
    504         rc = kldrDyldModAddDep(*ppMod, pDep);
     930        g_papStackMods[g_cStackMods++] = pMod;
    505931    return rc;
    506932}
     
    508934
    509935/**
    510  * Worker for kLdrDyldLoad() and helper for kLdrDyldLoadExe().
    511  * @internal
    512  */
    513 static int kldrDyldDoLoad(const char *pszDll, const char *pszDefPrefix, const char *pszDefSuffix, KLDRDYLDSEARCH enmSearch,
    514                           unsigned fFlags, PPKLDRDYLDMOD ppMod, char *pszErr, size_t cchErr)
    515 {
    516     int         rc;
    517 
    518     /*
    519      * Try find the module among the ones that's already loaded.
    520      */
    521     rc = kldrDyldFindExistingModule(pszDll, pszDefPrefix, pszDefSuffix, enmSearch, fFlags, ppMod);
    522     if (!rc)
     936 * The frame has been completed.
     937 *
     938 * @returns Where the frame ends.
     939 */
     940static int kldrDyldStackFrameCompleted(void)
     941{
     942    return g_cStackMods;
     943}
     944
     945
     946/**
     947 * Done with the stack frame, dereference all the modules in it.
     948 *
     949 * @param   iLoad1st        The start of the stack frame.
     950 * @param   iLoadEnd        The end of the stack frame.
     951 * @param   rc              Used for state verification.
     952 */
     953static void kldrDyldStackDropFrame(uint32_t iLoad1st, uint32_t iLoadEnd, int rc)
     954{
     955    uint32_t iStack;
     956    KLDRDYLD_ASSERT(iLoadEnd <= g_cStackMods);
     957    KLDRDYLD_ASSERT(iLoad1st == g_cStackMods);
     958
     959    /*
     960     * First pass: Do all the cleanups we can, but don't destroy anything just yet.
     961     */
     962    for (iStack = iLoadEnd; iStack < iLoad1st; iStack++)
     963    {
     964        PKLDRDYLDMOD pMod = g_papStackMods[--iLoad1st];
     965        switch (pMod->enmState)
     966        {
     967            /*
     968             * Just push it along to the PENDING_DESTROY state.
     969             */
     970            case KLDRSTATE_MAPPED:
     971                KLDRDYLD_ASSERT(rc);
     972                kldrDyldModUnmap(pMod);
     973                KLDRDYLD_ASSERT(pMod->enmState == KLDRSTATE_PENDING_DESTROY);
     974                break;
     975
     976            /*
     977             * Move back to PENDING_GC.
     978             */
     979            case KLDRSTATE_RELOADED:
     980                KLDRDYLD_ASSERT(rc);
     981                pMod->enmState = KLDRSTATE_PENDING_GC;
     982                break;
     983
     984            /*
     985             * Unload prerequisites and unmap the modules.
     986             */
     987            case KLDRSTATE_LOADED_PREREQUISITES:
     988            case KLDRSTATE_FIXED_UP:
     989                KLDRDYLD_ASSERT(rc);
     990                kldrDyldModUnloadPrerequisites(pMod);
     991                KLDRDYLD_ASSERT(pMod->enmState == KLDRSTATE_PENDING_DESTROY);
     992                kldrDyldModUnmap(pMod);
     993                KLDRDYLD_ASSERT(pMod->enmState == KLDRSTATE_PENDING_DESTROY);
     994                break;
     995
     996            /*
     997             * Unload prerequisites and push it back to PENDING_GC.
     998             */
     999            case KLDRSTATE_RELOADED_LOADED_PREREQUISITES:
     1000            case KLDRSTATE_RELOADED_FIXED_UP:
     1001                kldrDyldModUnloadPrerequisites(pMod);
     1002                KLDRDYLD_ASSERT(pMod->enmState == KLDRSTATE_PENDING_GC);
     1003                break;
     1004
     1005            /*
     1006             * Nothing to do, just asserting sanity.
     1007             */
     1008            case KLDRSTATE_INITIALIZING:
     1009                /* Implies there is another load going on. */
     1010                KLDRDYLD_ASSERT(g_cActiveLoadCalls > 1);
     1011                break;
     1012            case KLDRSTATE_TERMINATING:
     1013                /* GC in progress. */
     1014                KLDRDYLD_ASSERT(g_fActiveGC);
     1015                break;
     1016            case KLDRSTATE_PENDING_TERMINATION:
     1017            case KLDRSTATE_PENDING_INITIALIZATION:
     1018            case KLDRSTATE_PENDING_GC:
     1019            case KLDRSTATE_PENDING_DESTROY:
     1020                KLDRDYLD_ASSERT(rc);
     1021                break;
     1022            case KLDRSTATE_GOOD:
     1023                break;
     1024
     1025            /*
     1026             * Bad states.
     1027             */
     1028            default:
     1029                KLDRDYLD_ASSERT(!"drop frame bad state (a)");
     1030                break;
     1031        }
     1032    }
     1033
     1034    /*
     1035     * Second pass: Release the references so modules pending destruction
     1036     *              can be completely removed.
     1037     */
     1038    while (iLoad1st > iLoadEnd)
    5231039    {
    5241040        /*
    525          * Because of initialization and termination routines this
    526          * get's kind of complicated. Even if the module is loaded,
    527          * we might end up having to resolve all dependencies to check
    528          * whether reloading or/and initialization is required.
     1041         * Pop a module.
    5291042         */
    530         switch ((*ppMod)->enmState)
    531         {
    532             /*
    533              * Prerequisites are ok, so nothing to do really.
    534              */
     1043        PKLDRDYLDMOD pMod = g_papStackMods[--iLoad1st];
     1044        g_cStackMods = iLoad1st;
     1045
     1046        /*
     1047         * Revalidate the module state.
     1048         */
     1049        switch (pMod->enmState)
     1050        {
     1051            case KLDRSTATE_INITIALIZING:
     1052            case KLDRSTATE_TERMINATING:
     1053            case KLDRSTATE_PENDING_TERMINATION:
     1054            case KLDRSTATE_PENDING_INITIALIZATION:
     1055            case KLDRSTATE_PENDING_GC:
     1056            case KLDRSTATE_PENDING_DESTROY:
    5351057            case KLDRSTATE_GOOD:
    536             case KLDRSTATE_INITIALIZING:
    537                 return kldrDyldModDynamicLoad(*ppMod);
    538 
    539             /*
    540              * Prerequisites needs checking.
    541              */
    542             case KLDRSTATE_PENDING_INITIALIZATION:
    543                 (*ppMod)->fAlreadySeen = 0;
    544             case KLDRSTATE_PENDING_TERMINATION:
    545                 break;
    546 
    547             /*
    548              * The module has been terminated so it need to be reloaded, have it's
    549              * prereqs loaded, fixed up and initialized before we can use it again.
    550              */
    551             case KLDRSTATE_PENDING_GC:
    552                 rc = kldrDyldModReload(*ppMod);
    553                 if (rc)
    554                     return kldrDyldCopyError(rc, pszErr, cchErr);
    555                 break;
    556 
    557             /*
    558              * Forget it, we don't know how to deal with re-initialization here.
    559              */
    560             case KLDRSTATE_TERMINATING:
    561                 KLDRDYLD_ASSERT(!"KLDR_ERR_MODULE_TERMINATING");
    562                 return KLDR_ERR_MODULE_TERMINATING;
    563 
    564             /*
    565              * Invalid state.
    566              */
     1058                break;
    5671059            default:
    568                 KLDRDYLD_ASSERT(!"invalid state");
    569                 break;
    570         }
    571     }
    572     else
    573     {
     1060                KLDRDYLD_ASSERT(!"drop frame bad state (b)");
     1061                break;
     1062        }
     1063
    5741064        /*
    575          * We'll have to load it from file.
     1065         * Release it.
    5761066         */
    577         rc = kldrDyldFindNewModule(pszDll, pszDefPrefix, pszDefSuffix, enmSearch, fFlags, ppMod);
    578         if (rc)
    579             return kldrDyldCopyError(rc, pszErr, cchErr);
    580         rc = kldrDyldModMap(*ppMod);
    581     }
    582 
    583     if (!rc)
     1067        kldrDyldModDeref(pMod);
     1068    }
     1069}
     1070
     1071
     1072/**
     1073 * Do garbage collection.
     1074 *
     1075 * This isn't doing anything unless it's called from the last
     1076 * load or unload call.
     1077 */
     1078static void kldrDyldDoModuleTerminationAndGarabageCollection(void)
     1079{
     1080    PKLDRDYLDMOD pMod;
     1081
     1082    /*
     1083     * We don't do anything until we're got rid of all recursive calls.
     1084     * This will ensure that we get the most optimal termination order and
     1085     * that we don't unload anything too early.
     1086     */
     1087    if (g_cActiveLoadCalls || g_cActiveUnloadCalls || g_fActiveGC)
     1088        return;
     1089    g_fActiveGC = 1;
     1090
     1091    do
    5841092    {
    5851093        /*
    586          * Create the stack frame of modules by resolving module prerequisites.
     1094         * 1. Release prerequisites for any left over modules.
    5871095         */
    588         uint32_t iStackBottom = kldrDyldStackNewFrame();
    589         uint32_t iStack = iStackBottom;
    590         uint32_t iStackTop;
    591         rc = kldrDyldStackPushModule(*ppMod);
    592         while (!rc && iStack < g_cStackMods /* changes while we're in the loop */)
    593         {
    594             PKLDRDYLDMOD pMod = g_papStackMods[iStack];
     1096        for (pMod = kLdrDyldHead; pMod; pMod = pMod->Load.pNext);
     1097        {
     1098            kldrDyldModAddRef(pMod);
     1099
    5951100            switch (pMod->enmState)
    5961101            {
    597                 /*
    598                  * Load immediate prerequisite modules and push the ones needing
    599                  * attention onto the stack.
    600                  */
    601                 case KLDRSTATE_MAPPED:
    602                 case KLDRSTATE_RELOADED:
    603                     rc = kldrDyldModLoadPrerequisites(pMod, pszDll, pszDefPrefix, pszDefSuffix, enmSearch, fFlags);
     1102                case KLDRSTATE_GOOD:
     1103                case KLDRSTATE_PENDING_GC:
    6041104                    break;
    6051105
    606                 /*
    607                  * Check dependencies.
    608                  */
     1106                case KLDRSTATE_INITIALIZATION_FAILED: /* just in case */
     1107                case KLDRSTATE_PENDING_INITIALIZATION:
    6091108                case KLDRSTATE_PENDING_TERMINATION:
    610                     rc = kldrDyldModCheckPrerequisites(pMod);
     1109                    kldrDyldModUnloadPrerequisites(pMod);
    6111110                    break;
    6121111
    613                 /*
    614                  * Check its prerequisite modules the first time around.
    615                  */
    616                 case KLDRSTATE_PENDING_INITIALIZATION:
    617                     if (!pMod->fAlreadySeen)
    618                     {
    619                         pMod->fAlreadySeen = 1;
    620                         rc = kldrDyldModCheckPrerequisites(pMod);
    621                     }
    622                     break;
    623 
    624                 /*
    625                  * These are ok.
    626                  */
    627                 case KLDRSTATE_LOADED_PREREQUISITES:
    628                 case KLDRSTATE_INITIALIZING:
    629                 case KLDRSTATE_GOOD:
    630                     break;
    631 
    632                 /*
    633                  * All other stats are invalid.
    634                  */
    6351112                default:
    636                     KLDRDYLD_ASSERT(!"invalid state");
     1113                    KLDRDYLD_ASSERT(!"invalid GC state (a)");
    6371114                    break;
    6381115            }
    6391116
    640             /* next */
    641             iStack++;
    642         }
    643         iStackTop = kldrDyldStackFrameCompleted();
     1117            kldrDyldModDeref(pMod);
     1118        }
    6441119
    6451120        /*
    646          * Apply fixups.
     1121         * 2. Do init calls until we encounter somebody calling load/unload.
    6471122         */
    648         for (iStack = iStackBottom; !rc && iStack < iStackTop; iStack++)
    649         {
    650             PKLDRDYLDMOD pMod = g_papStackMods[iStack];
    651             if (pMod->enmState == KLDRSTATE_LOADED_PREREQUISITES)
    652                 rc = kldrDyldModFixup(pMod);
    653 
    654         }
    655 #ifdef KLDRDYLD_STRICT
    656         if (!rc)
    657             for (iStack = iStackBottom; !rc && iStack < iStackTop; iStack++)
    658                 KLDRDYLD_ASSERT(g_papStackMods[iStack]->enmState >= KLDRSTATE_FIXED_UP);
    659 #endif
    660 
    661         /*
    662          * Call the initializers (LIFO order).
    663          */
    664         iStack = iStackBottom;
    665         while (!rc && iStack-- > iStackTop)
    666         {
    667             PKLDRDYLDMOD pMod = g_papStackMods[iStack];
    668             if (pMod->enmState == KLDRSTATE_PENDING_INITIALIZATION)
    669                 rc = kldrDyldModCallInit(pMod);
    670         }
    671 #ifdef KLDRDYLD_STRICT
    672         if (!rc)
    673             for (iStack = iStackBottom; !rc && iStack < iStackTop; iStack++)
    674                 KLDRDYLD_ASSERT(g_papStackMods[iStack]->enmState == KLDRSTATE_GOOD);
    675 #endif
    676 
    677         /*
    678          * Complete the load by incrementing the dynamic load count of the
    679          * requested module (return handle is already set).
    680          */
    681         if (!rc)
    682         {
    683             rc = kldrDyldModDynamicLoad(*ppMod);
    684             if (!rc)
     1123        for (pMod = g_pkLdrDyldTermHead; pMod; pMod = pMod->InitTerm.pNext)
     1124        {
     1125            int fRestart = 0;
     1126            kldrDyldModAddRef(pMod);
     1127
     1128            switch (pMod->enmState)
    6851129            {
    686                 kldrDyldStackDropFrame(iStackTop, iStackBottom, rc);
    687                 kldrDyldModDeref(*ppMod);
    688                 return rc;
     1130                case KLDRSTATE_GOOD:
     1131                case KLDRSTATE_PENDING_GC:
     1132                    break;
     1133
     1134                case KLDRSTATE_PENDING_TERMINATION:
     1135                {
     1136                    const uint32_t cTotalLoadCalls = g_cTotalLoadCalls;
     1137                    const uint32_t cTotalUnloadCalls = g_cTotalUnloadCalls;
     1138                    kldrDyldModCallTerm(pMod);
     1139                    fRestart = cTotalLoadCalls != g_cTotalLoadCalls
     1140                            || cTotalUnloadCalls != g_cTotalUnloadCalls;
     1141                    break;
     1142                }
     1143
     1144                default:
     1145                    KLDRDYLD_ASSERT(!"invalid GC state (b)");
     1146                    break;
    6891147            }
    690         }
    691         kldrDyldStackDropFrame(iStackTop, iStackBottom, rc);
    692     }
    693     else
    694     {
    695         /* If the reference count is 0 do a quick ref/deref to trigger destruction. */
    696         kldrDyldModAddRef(*ppMod);
    697         kldrDyldModDeref(*ppMod);
    698     }
    699 
    700     /*
    701      * We've failed, copy/create error string.
    702      */
    703     return kldrDyldCopyError(rc, pszErr, cchErr);
     1148
     1149            kldrDyldModDeref(pMod);
     1150            if (fRestart)
     1151                break;
     1152        }
     1153    } while (pMod);
     1154
     1155    /*
     1156     * Unmap and destroy modules pending for GC.
     1157     */
     1158    pMod = kLdrDyldHead;
     1159    while (pMod)
     1160    {
     1161        PKLDRDYLDMOD pNext = pMod->Load.pNext;
     1162        switch (pMod->enmState)
     1163        {
     1164            case KLDRSTATE_INITIALIZATION_FAILED:
     1165            case KLDRSTATE_PENDING_GC:
     1166                KLDRDYLD_ASSERT(pMod->cRefs == 0); /* ??? */
     1167                pMod->enmState = KLDRSTATE_GC;
     1168                kldrDyldModUnmap(pMod);
     1169                kldrDyldModDestroy(pMod);
     1170                break;
     1171
     1172            case KLDRSTATE_GOOD:
     1173                break;
     1174            default:
     1175                KLDRDYLD_ASSERT(!"invalid GC state (c)");
     1176                break;
     1177        }
     1178
     1179        /* next */
     1180        pMod = pNext;
     1181    }
     1182
     1183    g_fActiveGC = 0;
    7041184}
    7051185
     
    8761356
    8771357/**
    878  * Do garbage collection.
    879  *
    880  * This isn't doing anything unless it's called from the last
    881  * load or unload call.
    882  */
    883 static void kldrDyldDoModuleTerminationAndGarabageCollection(void)
    884 {
    885     PKLDRDYLDMOD pMod;
    886 
    887     /*
    888      * We don't do anything untill we're got rid of all re-entrant calls.
    889      * This will ensure that we get the most optimal termination order and
    890      * that we don't unload anything too early.
    891      */
    892     if (g_cActiveLoadCalls || g_cActiveUnloadCalls || g_fActiveGC)
    893         return;
    894     g_fActiveGC = 1;
    895 
    896     /*
    897      * Release prerequisites to maximize the number of term calls pending.
    898      */
    899     for (pMod = kLdrDyldHead; pMod; pMod = pMod->Load.pNext);
    900     {
    901         kldrDyldModAddRef(pMod);
    902 
    903         switch (pMod->enmState)
    904         {
    905             case KLDRSTATE_GOOD:
    906             case KLDRSTATE_PENDING_GC:
    907                 break;
    908 
    909             case KLDRSTATE_PENDING_INITIALIZATION:
    910             case KLDRSTATE_PENDING_TERMINATION:
    911                 kldrDyldModUnloadPrerequisites(pMod);
    912                 break;
    913 
    914             default:
    915                 KLDRDYLD_ASSERT(!"invalid GC state (a)");
    916                 break;
    917         }
    918 
    919         kldrDyldModDeref(pMod);
    920     }
    921 
    922     /*
    923      * Do termination calls (FIFO order) process new unloads.
    924      * The current algorithm here is a bit sluggish, but it ensure correct order.
    925      */
    926     do
    927     {
    928         for (pMod = g_pkLdrDyldTermHead; pMod; pMod = pMod->Term.pNext)
    929         {
    930             int fRestart = 0;
    931             kldrDyldModAddRef(pMod);
    932 
    933             switch (pMod->enmState)
    934             {
    935                 case KLDRSTATE_GOOD:
    936                 case KLDRSTATE_PENDING_GC:
    937                     break;
    938 
    939                 case KLDRSTATE_PENDING_TERMINATION:
    940                     kldrDyldModUnloadPrerequisites(pMod);
    941                     kldrDyldModCallTerm(pMod);
    942                     fRestart = 1;
    943                     break;
    944 
    945                 case KLDRSTATE_PENDING_INITIALIZATION:
    946                     kldrDyldModUnloadPrerequisites(pMod);
    947                     break;
    948 
    949                 default:
    950                     KLDRDYLD_ASSERT(!"invalid GC state (b)");
    951                     break;
    952             }
    953 
    954             kldrDyldModDeref(pMod);
    955             if (fRestart)
    956                 break;
    957         }
    958     } while (pMod);
    959 
    960     /*
    961      * Unmap and destroy modules pending for GC.
    962      */
    963     pMod = kLdrDyldHead;
    964     while (pMod)
    965     {
    966         PKLDRDYLDMOD pNext = pMod->Load.pNext;
    967         switch (pMod->enmState)
    968         {
    969             case KLDRSTATE_PENDING_GC:
    970                 kldrDyldModAddRef(pMod);
    971                 KLDRDYLD_ASSERT(pMod->cRefs == 1);
    972 
    973                 pMod->enmState = KLDRSTATE_GC;
    974                 kldrDyldModUnmap(pMod);
    975 
    976                 KLDRDYLD_ASSERT(pMod->enmState == KLDRSTATE_PENDING_DESTROY);
    977                 kldrDyldModDeref(pMod);
    978                 break;
    979 
    980             /* the only other state that's valid at this point. */
    981             case KLDRSTATE_GOOD:
    982                 break;
    983 
    984             /* all other stats are invalid. */
    985             default:
    986                 KLDRDYLD_ASSERT(!"invalid GC state (c)");
    987                 break;
    988         }
    989 
    990         /* next */
    991         pMod = pNext;
    992     }
    993 
    994     g_fActiveGC = 0;
    995 }
    996 
    997 
    998 
    999 /**
    1000  * Starts loading a new module and its dependencies.
    1001  * @returns Where the new stack frame starts.
    1002  */
    1003 static uint32_t kldrDyldStackNewFrame(void)
    1004 {
    1005 #ifdef KLDRDYLD_STRICT
    1006     /* check that all modules are in the correct state */
    1007     PKLDRDYLDMOD pMod = kLdrDyldHead;
    1008     while (pMod)
    1009     {
    1010         //KLDRDYLD_ASSERT(pMod->enmState == KLDRSTATE_LOADED);
    1011 
    1012         /* next */
    1013         pMod = pMod->Load.pNext;
    1014     }
    1015 #endif
    1016     return g_cStackMods;
    1017 }
    1018 
    1019 
    1020 /**
    1021  * Records the module.
    1022  *
    1023  * @return 0 on success, KLDR_ERR_NO_MEMORY if we can't expand the table.
    1024  * @param   pMod        The module to record.
    1025  */
    1026 int kldrDyldStackPushModule(PKLDRDYLDMOD pMod)
    1027 {
    1028     int rc;
    1029 
    1030     /*
    1031      * Grow the stack if necessary.
    1032      */
    1033     if (g_cStackMods + 1 > g_cStackModsAllocated)
    1034     {
    1035         uint32_t cNew = g_cStackModsAllocated ? g_cStackModsAllocated * 2 : 128;
    1036         void *pvOld = g_papStackMods;
    1037         void *pvNew = kldrHlpAlloc(cNew * sizeof(g_papStackMods[0]));
    1038         if (!pvNew)
    1039             return KLDR_ERR_NO_MEMORY;
    1040         kLdrHlpMemCopy(pvNew, pvOld, g_cStackMods * sizeof(g_papStackMods[0]));
    1041         g_papStackMods = (PPKLDRDYLDMOD)pvNew;
    1042         kldrHlpFree(pvOld);
    1043     }
    1044 
    1045     /*
    1046      * Add a reference and push the module onto the stack.
    1047      */
    1048     rc = kldrDyldModAddRef(pMod);
    1049     if (!rc)
    1050         g_papStackMods[g_cStackMods++] = pMod;
    1051     return rc;
    1052 }
    1053 
    1054 
    1055 /**
    1056  * The frame has been completed.
    1057  *
    1058  * @returns Where the frame ends.
    1059  */
    1060 static int kldrDyldStackFrameCompleted(void)
    1061 {
    1062     return g_cStackMods;
    1063 }
    1064 
    1065 
    1066 /**
    1067  * Done with the stack frame, dereference all the module in it.
    1068  *
    1069  * @param   iStackTop       The top of the stack frame.
    1070  * @param   iStackBottom    The bottom of the stack frame.
    1071  * @param   rc              Used for state verification.
    1072  */
    1073 static void kldrDyldStackDropFrame(uint32_t iStackTop, uint32_t iStackBottom, int rc)
    1074 {
    1075     uint32_t iStack;
    1076     KLDRDYLD_ASSERT(iStackBottom <= g_cStackMods);
    1077     KLDRDYLD_ASSERT(iStackTop == g_cStackMods);
    1078 
    1079     /*
    1080      * First pass, cleanup modules in an obvious 'failed' state so we don't
    1081      * leave any of the non-reentrant states behind.
    1082      */
    1083     for (iStack = iStackBottom; iStack < iStackTop; iStack++)
    1084     {
    1085         PKLDRDYLDMOD pMod = g_papStackMods[--iStackTop];
    1086         switch (pMod->enmState)
    1087         {
    1088             /*
    1089              * Unmap freshly mapped so it can be destroyed.
    1090              */
    1091             case KLDRSTATE_MAPPED:
    1092                 KLDRDYLD_ASSERT(rc);
    1093                 kldrDyldModUnmap(pMod);
    1094                 KLDRDYLD_ASSERT(pMod->enmState == KLDRSTATE_PENDING_DESTROY);
    1095                 break;
    1096 
    1097             /*
    1098              * Reload is reverted to it's old state.
    1099              */
    1100             case KLDRSTATE_RELOADED:
    1101                 KLDRDYLD_ASSERT(rc);
    1102                 pMod->enmState = KLDRSTATE_PENDING_GC;
    1103                 break;
    1104 
    1105             /*
    1106              * Unload prerequisites and unmap modules loaded in this frame.
    1107              */
    1108             case KLDRSTATE_LOADED_PREREQUISITES:
    1109             case KLDRSTATE_FIXED_UP: /** @todo fix reload state mess. */
    1110                 KLDRDYLD_ASSERT(rc);
    1111                 kldrDyldModUnloadPrerequisites(pMod);
    1112                 KLDRDYLD_ASSERT(pMod->enmState == KLDRSTATE_PENDING_GC);
    1113                 kldrDyldModUnmap(pMod);
    1114                 KLDRDYLD_ASSERT(pMod->enmState == KLDRSTATE_PENDING_DESTROY);
    1115                 break;
    1116 
    1117             /*
    1118              * Ok states.
    1119              */
    1120             case KLDRSTATE_INITIALIZING:
    1121                 KLDRDYLD_ASSERT(g_cActiveLoadCalls > 0);
    1122                 break;
    1123             case KLDRSTATE_TERMINATING:
    1124                 KLDRDYLD_ASSERT(rc);
    1125                 KLDRDYLD_ASSERT(g_fActiveGC);
    1126                 break;
    1127             case KLDRSTATE_PENDING_TERMINATION:
    1128             case KLDRSTATE_PENDING_INITIALIZATION:
    1129             case KLDRSTATE_PENDING_GC:
    1130             case KLDRSTATE_PENDING_DESTROY:
    1131                 KLDRDYLD_ASSERT(rc);
    1132                 break;
    1133             case KLDRSTATE_GOOD:
    1134                 break;
    1135 
    1136             /*
    1137              * Bad states.
    1138              */
    1139             default:
    1140                 KLDRDYLD_ASSERT(!"drop frame bad state (a)");
    1141                 break;
    1142         }
    1143     }
    1144 
    1145     /*
    1146      * Second pass, release the references to the modules on the stack.
    1147      */
    1148     while (iStackTop > iStackBottom)
    1149     {
    1150         /*
    1151          * Pop a module.
    1152          */
    1153         PKLDRDYLDMOD pMod = g_papStackMods[--iStackTop];
    1154         g_cStackMods = iStackTop;
    1155 
    1156         /*
    1157          * Validate the state.
    1158          */
    1159         switch (pMod->enmState)
    1160         {
    1161             /*
    1162              * Ok states
    1163              */
    1164             case KLDRSTATE_INITIALIZING:
    1165                 KLDRDYLD_ASSERT(g_cActiveLoadCalls > 0);
    1166                 break;
    1167             case KLDRSTATE_TERMINATING:
    1168                 KLDRDYLD_ASSERT(rc);
    1169                 KLDRDYLD_ASSERT(g_fActiveGC);
    1170                 break;
    1171             case KLDRSTATE_PENDING_INITIALIZATION:
    1172             case KLDRSTATE_PENDING_TERMINATION:
    1173             case KLDRSTATE_PENDING_GC:
    1174             case KLDRSTATE_PENDING_DESTROY:
    1175                 KLDRDYLD_ASSERT(rc);
    1176                 break;
    1177             case KLDRSTATE_GOOD:
    1178                 break;
    1179 
    1180             /*
    1181              * Bad states.
    1182              */
    1183             default:
    1184                 KLDRDYLD_ASSERT(!"drop frame bad state (b)");
    1185                 break;
    1186         }
    1187 
    1188         /*
    1189          * Release it.
    1190          */
    1191         kldrDyldModDeref(pMod);
    1192     }
    1193 }
    1194 
    1195 
    1196 /**
    11971358 * Panic / failure
    11981359 *
  • trunk/kLdr/kLdrDyldMod.c

    r2837 r2842  
    4949
    5050
    51 
     51/**
     52 * Decrement the dynamic load count of the module and unload the module
     53 * if the total reference count reaches zero.
     54 *
     55 * This may cause a cascade of unloading to occure. See kldrDyldModUnloadPrerequisites().
     56 *
     57 * @returns status code.
     58 * @retval  0 on success.
     59 * @retval  KLDR_ERR_NOT_LOADED_DYNAMICALLY if the module wasn't loaded dynamically.
     60 * @param   pMod        The module to unload.
     61 */
     62int kldrDyldModDynamicUnload(PKLDRDYLDMOD pMod)
     63{
     64    if (pMod->cDynRefs == 0)
     65        return KLDR_ERR_NOT_LOADED_DYNAMICALLY;
     66    KLDRDYLDMOD_ASSERT(pMod->cDynRefs <= pMod->cRefs);
     67    KLDRDYLDMOD_ASSERT(pMod->enmState == KLDRSTATE_GOOD);
     68
     69    pMod->cRefs--;
     70    pMod->cDynRefs--;
     71    if (pMod->cRefs > 0)
     72        return 0;
     73
     74    /*
     75     * The module should be unloaded.
     76     */
     77    kldrDyldModUnloadPrerequisites(pMod);
     78    return 0;
     79}
     80
     81
     82/**
     83 * Worker for kldrDyldModUnloadPrerequisites.
     84 *
     85 * @returns The number of modules that now can be unloaded.
     86 * @param   pMod    The module in  question.
     87 */
     88static uint32_t kldrDyldModUnloadPrerequisitesOne(PKLDRDYLDMOD pMod)
     89{
     90    PKLDRDYLDMOD    pMod2;
     91    uint32_t        cToUnload = 0;
     92    uint32_t        i;
     93
     94    KLDRDYLDMOD_ASSERT(pMod->papPrereqs);
     95
     96    /*
     97     * Release the one in this module.
     98     */
     99    for (i = 0; i < pMod->cPrereqs; i++)
     100    {
     101        pMod2 = pMod->papPrereqs[i];
     102        if (pMod2)
     103        {
     104            /* do the derefering ourselves or we'll end up in a recursive loop here. */
     105            KLDRDYLDMOD_ASSERT(pMod2->cDepRefs > 0);
     106            KLDRDYLDMOD_ASSERT(pMod2->cRefs >= pMod2->cDepRefs);
     107            pMod2->cDepRefs--;
     108            pMod2->cRefs--;
     109            cToUnload += !pMod2->cRefs;
     110        }
     111    }
     112
     113    /*
     114     * Change the state
     115     */
     116    switch (pMod->enmState)
     117    {
     118        case KLDRSTATE_LOADED_PREREQUISITES:
     119        case KLDRSTATE_FIXED_UP:
     120            pMod->enmState = KLDRSTATE_PENDING_DESTROY;
     121            kldrDyldModUnlink(pMod);
     122            break;
     123
     124        case KLDRSTATE_PENDING_INITIALIZATION:
     125            pMod->enmState = KLDRSTATE_PENDING_GC;
     126            break;
     127
     128        case KLDRSTATE_RELOADED_FIXED_UP:
     129        case KLDRSTATE_RELOADED_LOADED_PREREQUISITES:
     130        case KLDRSTATE_GOOD:
     131            pMod->enmState = KLDRSTATE_PENDING_TERMINATION;
     132            break;
     133
     134        case KLDRSTATE_INITIALIZATION_FAILED:
     135            break;
     136
     137        default:
     138            KLDRDYLDMOD_ASSERT(!"invalid state");
     139            break;
     140    }
     141
     142    return cToUnload;
     143}
     144
     145
     146/**
     147 * This is the heart of the unload code.
     148 *
     149 * It will recursivly (using the load list) initiate module unloading
     150 * of all affected modules.
     151 *
     152 * This function will cause a state transition ot PENDING_DESTROY, PENDING_GC
     153 * or PENDING_TERMINATION depending on the module state. There is one exception
     154 * to this, and that's INITIALIZATION_FAILED, where the state will not be changed.
     155 *
     156 * @param   pMod        The module which prerequisites should be unloaded.
     157 */
    52158void kldrDyldModUnloadPrerequisites(PKLDRDYLDMOD pMod)
    53159{
    54 
    55 }
     160    uint32_t        cToUnload;
     161
     162    /* sanity */
     163#ifdef KLDRDYLD_STRICT
     164    {
     165    PKLDRDYLDMOD pMod2;
     166    for (pMod2 = kLdrDyldHead; pMod2; pMod2 = pMod2->Load.pNext)
     167        KLDRDYLDMOD_ASSERT(pMod2->enmState != KLDRSTATE_GOOD || pMod2->cRefs);
     168    }
     169#endif
     170    KLDRDYLDMOD_ASSERT(pMod->papPrereqs);
     171
     172    /*
     173     * Unload prereqs of the module we're called on first.
     174     */
     175    cToUnload = kldrDyldModUnloadPrerequisitesOne(pMod);
     176
     177    /*
     178     * Iterate the load list in a cyclic manner until there are no more
     179     * modules that can be pushed on into unloading.
     180     */
     181    while (cToUnload)
     182    {
     183        cToUnload = 0;
     184        for (pMod = kLdrDyldHead; pMod; pMod = pMod->Load.pNext)
     185        {
     186            if (    pMod->cRefs
     187                ||  pMod->enmState >= KLDRSTATE_PENDING_TERMINATION
     188                ||  pMod->enmState < KLDRSTATE_LOADED_PREREQUISITES)
     189                continue;
     190            cToUnload += kldrDyldModUnloadPrerequisitesOne(pMod);
     191        }
     192    }
     193}
     194
     195
     196
    56197
    57198
  • trunk/kLdr/kLdrHlp.c

    r2836 r2842  
    555555    ULONG       cbWritten;
    556556    const char *pszNl = kLdrHlpStrChr(pszMsg, '\n');
    557     while (pszNl || *pszMsg)
     557    while (pszNl)
    558558    {
    559559        cbWritten = pszNl - pszMsg;
  • trunk/kLdr/kLdrInternal.h

    r2840 r2842  
    164164    /** Pending termination, reference count is 0.
    165165     * While the module is in this state the loader is in reentrant mode.
     166     * Prerequisite modules are dropped when a module enters this state.
    166167     *
    167168     * Prev state: GOOD
     
    179180
    180181    /** Pending garbage collection.
     182     * Prerequisite modules are dropped when a module enters this state (if not done already).
    181183     *
    182184     * Prev state: TERMINATING, PENDING_INITIALIZATION, INITIALIZATION_FAILED
     
    238240    /** Whether the module contains bindable symbols in the global unix namespace. */
    239241    uint32_t            fBindable : 1;
     242    /** Set if linked into the global init list. */
     243    uint32_t            fInitList : 1;
     244    /** Already loaded or checked prerequisites.
     245     * This flag is used when loading prerequisites, when set it means that
     246     * this module is already seen and shouldn't be processed again. */
     247    uint32_t            fAlreadySeen : 1;
    240248    /** Reserved for future use. */
    241     uint32_t            fReserved : 28;
    242     /** Already checked dependencies.
    243      * This is flag used when resolving module dependencies during a load, it
    244      * deals with modules in the KLDRSTATE_PENDING_INITIALIZATION state. */
    245     uint32_t            fAlreadySeen : 1;
     249    uint32_t            fReserved : 27;
    246250    /** The load list linkage. */
    247251    struct
     
    252256        struct KLDRDYLDMOD *pPrev;
    253257    } Load;
    254     /** The termination list linkage.
     258    /** The initialization and termination list linkage.
     259     * If non-recursive initialization is used, the module will be pushed on
     260     * the initialization list.
    255261     * A module will be linked into the termination list upon a successful
    256262     * return from module initialization. */
     
    261267        /** The prev module in the list. */
    262268        struct KLDRDYLDMOD *pPrev;
    263     } Term;
     269    } InitTerm;
    264270    /** The bind order list linkage.
    265271     * The module is not in this list when fBindable is clear. */
     
    271277        struct KLDRDYLDMOD *pPrev;
    272278    } Bind;
     279
     280    /** The number of prerequisite modules in the prereq array. */
     281    uint32_t            cPrereqs;
     282    /** Pointer to an array of prerequisite module pointers.
     283     * This array is only filled when in the states starting with
     284     * KLDRSTATE_LOADED_PREREQUISITES thru KLDRSTATE_GOOD.
     285     */
     286    struct KLDRDYLDMOD **papPrereqs;
     287
    273288    /** Magic number. */
    274289    uint32_t            u32MagicTail;
     
    312327int kldrDyldModMap(PKLDRDYLDMOD pMod);
    313328int kldrDyldModUnmap(PKLDRDYLDMOD pMod);
    314 int kldrDyldModLoadPrerequisites(PKLDRDYLDMOD pMod, const char *pszName, const char *pszDefPrefix, const char *pszDefSuffix,
     329int kldrDyldModLoadPrerequisites(PKLDRDYLDMOD pMod, const char *pszDefPrefix, const char *pszDefSuffix,
    315330                                 KLDRDYLDSEARCH enmSearch, unsigned fFlags);
    316331int kldrDyldModCheckPrerequisites(PKLDRDYLDMOD pMod);
     
    333348
    334349
    335 /** Pointer to the head module of the load list (the executable). */
    336 extern PKLDRDYLDMOD     kLdrDyldModuleHead;
    337 /** Pointer to the tail module of the load list. */
    338 extern PKLDRDYLDMOD     kLdrDyldModuleTail;
     350/** Pointer to the head module (the executable).
     351 * (This is exported, so no prefix.) */
     352extern PKLDRDYLDMOD     kLdrDyldHead;
     353/** Pointer to the tail module.
     354 * (This is exported, so no prefix.) */
     355extern PKLDRDYLDMOD     kLdrDyldTail;
    339356/** Pointer to the head module of the termination order list. */
    340357extern PKLDRDYLDMOD     g_pkLdrDyldTermHead;
  • trunk/kLdr/tg/KLDRSTATE.txvstc

    r2840 r2842  
    463463        </link>
    464464        <link uin="id83t9setug73fpetug74ah.nodeidswftetug73fpetugfwd3.linkid7ockpetuqdc66etuqdq4c">
    465             <property name="$metaclass" value="Transition"/>
    466465            <participant role="Supplier" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid8048etug73fpetugfpwv"/>
    467466            <participant role="Client" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeidswftetug73fpetugfwd3"/>
     467            <property name="$metaclass" value="Transition"/>
    468468            <property name="$event_name" value="Loaded again"/>
    469469        </link>
  • trunk/kLdr/tg/kLdr.tpr

    r2840 r2842  
    1414Developer.DebugWorkspace={{0,2,-1,0,0,0,0,0,0,1,0,50,75,25,-1,-1,-1,-1}${0,1,-1,0,0,0,0,1,0,1,1,50,75,25,-1,-1,-1,-1}${0,3,-1,0,0,0,0,0,0,1,0,50,50,25,-1,-1,-1,-1}${0,3,-1,0,0,0,0,0,0,1,0,50,50,25,-1,-1,-1,-1}${0,-1,-1,0,0,0,0,0,0,1,0,5,5,5,-1,-1,-1,-1}${0,4,-1,0,0,0,0,0,0,1,0,50,50,25,-1,-1,-1,-1}${0,0,-1,0,0,0,0,1,0,1,0,75,5,5,-1,-1,-1,-1}${0,7,-1,0,0,0,0,0,0,1,0,50,50,75,-1,-1,-1,-1}}
    1515Developer.DesignWorkspace={{0,2,-1,0,0,0,0,1,0,1,0,50,75,22,-1,-1,-1,-1}${0,1,-1,0,0,0,0,0,0,1,0,50,75,22,-1,-1,-1,-1}${0,3,-1,0,0,0,0,1,0,1,0,50,50,22,-1,-1,-1,-1}${0,3,-1,0,0,0,0,1,0,1,0,50,50,22,-1,-1,-1,-1}${0,-1,-1,0,0,0,0,0,0,1,0,5,5,5,-1,-1,-1,-1}${0,4,-1,0,0,0,0,1,0,1,1,50,50,22,-1,-1,-1,-1}${0,0,-1,0,0,0,0,0,0,1,0,75,5,5,-1,-1,-1,-1}${0,7,-1,0,0,0,0,0,0,1,0,50,50,75,-1,-1,-1,-1}}
    16 Developer.kLdr={{0,2,-1,0,0,0,0,1,0,1,0,50,75,25,-1,-1,-1,-1}${0,1,-1,0,0,0,0,0,0,1,0,50,75,25,-1,-1,-1,-1}${0,3,-1,0,0,0,0,1,0,1,1,50,50,25,-1,-1,-1,-1}${0,3,-1,0,0,0,0,1,0,1,1,50,50,25,-1,-1,-1,-1}${0,-1,-1,0,0,0,0,0,0,1,0,5,5,5,-1,-1,-1,-1}${0,4,-1,0,0,0,0,1,0,1,0,50,50,25,-1,-1,-1,-1}${0,0,-1,0,0,0,0,0,0,1,0,75,5,5,-1,-1,-1,-1}${0,7,-1,0,0,0,0,0,0,1,0,50,50,75,-1,-1,-1,-1}}
     16Developer.kLdr={{0,2,-1,0,0,0,0,1,0,1,1,50,75,22,-1,-1,-1,-1}${0,1,-1,0,0,0,0,0,0,1,0,50,75,22,-1,-1,-1,-1}${0,3,-1,0,0,0,0,1,0,1,0,50,50,22,-1,-1,-1,-1}${0,3,-1,0,0,0,0,1,0,1,0,50,50,22,-1,-1,-1,-1}${0,-1,-1,0,0,0,0,0,0,1,0,5,5,5,-1,-1,-1,-1}${0,4,-1,0,0,0,0,1,0,1,0,50,50,22,-1,-1,-1,-1}${0,0,-1,0,0,0,0,0,0,1,0,75,5,5,-1,-1,-1,-1}${0,7,-1,0,0,0,0,0,0,1,0,50,50,75,-1,-1,-1,-1}}
    1717names.Developer={kLdr,DesignWorkspace,CodingWorkspace,DebugWorkspace}
    1818[vcs]
Note: See TracChangeset for help on using the changeset viewer.