Changeset 2842
- Timestamp:
- Oct 30, 2006, 1:49:15 AM (19 years ago)
- Location:
- trunk/kLdr
- Files:
-
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/kLdr/kLdr.h
r2840 r2842 545 545 /** Returns ALL kinds of symbols. The default is to only return public/exported symbols. */ 546 546 #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 547 549 /** @} */ 548 550 … … 734 736 735 737 /** 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) 737 739 /** 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) 739 743 /** 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) 741 745 /** 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) 743 747 /** 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) 745 749 /** 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) 749 763 750 764 751 765 /** 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) 753 770 754 771 /** @} */ -
trunk/kLdr/kLdrDyld.c
r2837 r2842 49 49 # define KLDRDYLD_ASSERT(expr) do {} while (0) 50 50 #endif 51 52 53 /******************************************************************************* 54 * Structures and Typedefs * 55 *******************************************************************************/ 51 56 52 57 … … 60 65 * (This is exported, so no prefix.) */ 61 66 PKLDRDYLDMOD 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. */ 73 PKLDRDYLDMOD g_pkLdrDyldInitHead; 74 /** Pointer to the tail module of the initalization list. */ 75 PKLDRDYLDMOD g_pkLdrDyldInitTail; 62 76 /** Pointer to the head module of the termination order list. */ 63 77 PKLDRDYLDMOD g_pkLdrDyldTermHead; … … 98 112 /** Number of active unload calls. */ 99 113 static uint32_t g_cActiveUnloadCalls; 114 /** Total number of load calls. */ 115 static uint32_t g_cTotalLoadCalls; 116 /** Total mumber of unload calls. */ 117 static uint32_t g_cTotalUnloadCalls; 100 118 /** Boolean flag indicating that GC is active. */ 101 119 static uint32_t g_fActiveGC; 102 103 120 104 121 /** The global error buffer. */ … … 115 132 * Internal Functions * 116 133 *******************************************************************************/ 134 /** @name API worker routines. 135 * @internal 136 * @{ */ 117 137 static int kldrDyldDoLoad(const char *pszDll, const char *pszDefPrefix, const char *pszDefSuffix, KLDRDYLDSEARCH enmSearch, 118 138 unsigned fFlags, PPKLDRDYLDMOD ppMod, char *pszErr, size_t cchErr); 139 static int kldrDyldDoLoadPrerequisites(PKLDRDYLDMOD pMod, const char *pszDefPrefix, const char *pszDefSuffix, 140 KLDRDYLDSEARCH enmSearch, unsigned fFlags); 119 141 static int kldrDyldDoUnload(PKLDRDYLDMOD pMod); 120 142 static int kldrDyldDoFindByName(const char *pszDll, const char *pszDefPrefix, const char *pszDefSuffix, KLDRDYLDSEARCH enmSearch, … … 124 146 static int kldrDyldDoGetFilename(PKLDRDYLDMOD pMod, char *pszFilename, size_t cchFilename); 125 147 static 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 */ 154 static void kldrDyldDoModuleTerminationAndGarabageCollection(void); 155 /** @} */ 156 157 /** @name The load stack. 158 * @internal 159 * @{ */ 160 static uint32_t kldrDyldStackNewFrame(PKLDRDYLDMOD pMod); 161 static int kldrDyldStackAddModule(PKLDRDYLDMOD pMod); 162 static int kldrDyldStackFrameCompleted(void); 163 static void kldrDyldStackDropFrame(uint32_t iLoad1st, uint32_t iLoadEnd, int rc); 164 /** @} */ 165 166 static int kldrDyldCopyError(int rc, char *pszErr, size_t cchErr); 135 167 136 168 … … 192 224 { 193 225 PKLDRDYLDMOD pMod = NULL; 226 g_cTotalLoadCalls++; 194 227 g_cActiveLoadCalls++; 195 228 rc = kldrDyldDoLoad(pszDll, pszDefPrefix, pszDefSuffix, enmSearch, fFlags, phMod, pszErr, cchErr); … … 220 253 if (!rc) 221 254 { 255 g_cTotalUnloadCalls++; 222 256 g_cActiveUnloadCalls++; 223 257 rc = kldrDyldDoUnload(hMod); … … 404 438 405 439 /** 440 * Worker for kLdrDyldLoad() and helper for kLdrDyldLoadExe(). 441 * @internal 442 */ 443 static 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 */ 627 static 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 /** 406 748 * Gets prerequisite module. 407 749 * … … 421 763 unsigned fFlags, PKLDRDYLDMOD pDep, PPKLDRDYLDMOD ppMod) 422 764 { 423 int rc; 765 int rc; 766 PKLDRDYLDMOD pMod; 424 767 425 768 *ppMod = NULL; … … 427 770 /* 428 771 * 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); 431 778 if (!rc) 432 779 { 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: 442 791 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;451 792 case KLDRSTATE_PENDING_TERMINATION: 452 793 break; … … 457 798 */ 458 799 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. 475 812 */ 476 813 case KLDRSTATE_TERMINATING: 477 KLDRDYLD_ASSERT(!"KLDR_ERR_PREREQUISITE_MODULE_TERMINATING");478 814 return KLDR_ERR_PREREQUISITE_MODULE_TERMINATING; 479 815 … … 493 829 rc = kldrDyldFindNewModule(pszDll, pszDefPrefix, pszDefSuffix, enmSearch, fFlags, ppMod); 494 830 if (!rc) 495 rc = kldrDyldModMap( *ppMod);496 } 497 498 /* 499 * Push it onto the stack and add thedependency.831 rc = kldrDyldModMap(pMod); 832 } 833 834 /* 835 * On success add dependency. 500 836 */ 501 837 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 */ 853 static 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 */ 906 static 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); 503 929 if (!rc) 504 rc = kldrDyldModAddDep(*ppMod, pDep);930 g_papStackMods[g_cStackMods++] = pMod; 505 931 return rc; 506 932 } … … 508 934 509 935 /** 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 */ 940 static 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 */ 953 static 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) 523 1039 { 524 1040 /* 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. 529 1042 */ 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: 535 1057 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; 567 1059 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 574 1064 /* 575 * We'll have to load it from file.1065 * Release it. 576 1066 */ 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 */ 1078 static 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 584 1092 { 585 1093 /* 586 * Create the stack frame of modules by resolving module prerequisites.1094 * 1. Release prerequisites for any left over modules. 587 1095 */ 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 595 1100 switch (pMod->enmState) 596 1101 { 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: 604 1104 break; 605 1105 606 /* 607 * Check dependencies. 608 */ 1106 case KLDRSTATE_INITIALIZATION_FAILED: /* just in case */ 1107 case KLDRSTATE_PENDING_INITIALIZATION: 609 1108 case KLDRSTATE_PENDING_TERMINATION: 610 rc = kldrDyldModCheckPrerequisites(pMod);1109 kldrDyldModUnloadPrerequisites(pMod); 611 1110 break; 612 1111 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 */635 1112 default: 636 KLDRDYLD_ASSERT(!"invalid state");1113 KLDRDYLD_ASSERT(!"invalid GC state (a)"); 637 1114 break; 638 1115 } 639 1116 640 /* next */ 641 iStack++; 642 } 643 iStackTop = kldrDyldStackFrameCompleted(); 1117 kldrDyldModDeref(pMod); 1118 } 644 1119 645 1120 /* 646 * Apply fixups.1121 * 2. Do init calls until we encounter somebody calling load/unload. 647 1122 */ 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) 685 1129 { 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; 689 1147 } 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; 704 1184 } 705 1185 … … 876 1356 877 1357 /** 878 * Do garbage collection.879 *880 * This isn't doing anything unless it's called from the last881 * 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 and890 * 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 do927 {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_STRICT1006 /* 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 #endif1016 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't1081 * 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 states1163 */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 /**1197 1358 * Panic / failure 1198 1359 * -
trunk/kLdr/kLdrDyldMod.c
r2837 r2842 49 49 50 50 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 */ 62 int 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 */ 88 static 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 */ 52 158 void kldrDyldModUnloadPrerequisites(PKLDRDYLDMOD pMod) 53 159 { 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 56 197 57 198 -
trunk/kLdr/kLdrHlp.c
r2836 r2842 555 555 ULONG cbWritten; 556 556 const char *pszNl = kLdrHlpStrChr(pszMsg, '\n'); 557 while (pszNl || *pszMsg)557 while (pszNl) 558 558 { 559 559 cbWritten = pszNl - pszMsg; -
trunk/kLdr/kLdrInternal.h
r2840 r2842 164 164 /** Pending termination, reference count is 0. 165 165 * While the module is in this state the loader is in reentrant mode. 166 * Prerequisite modules are dropped when a module enters this state. 166 167 * 167 168 * Prev state: GOOD … … 179 180 180 181 /** Pending garbage collection. 182 * Prerequisite modules are dropped when a module enters this state (if not done already). 181 183 * 182 184 * Prev state: TERMINATING, PENDING_INITIALIZATION, INITIALIZATION_FAILED … … 238 240 /** Whether the module contains bindable symbols in the global unix namespace. */ 239 241 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; 240 248 /** 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; 246 250 /** The load list linkage. */ 247 251 struct … … 252 256 struct KLDRDYLDMOD *pPrev; 253 257 } 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. 255 261 * A module will be linked into the termination list upon a successful 256 262 * return from module initialization. */ … … 261 267 /** The prev module in the list. */ 262 268 struct KLDRDYLDMOD *pPrev; 263 } Term;269 } InitTerm; 264 270 /** The bind order list linkage. 265 271 * The module is not in this list when fBindable is clear. */ … … 271 277 struct KLDRDYLDMOD *pPrev; 272 278 } 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 273 288 /** Magic number. */ 274 289 uint32_t u32MagicTail; … … 312 327 int kldrDyldModMap(PKLDRDYLDMOD pMod); 313 328 int kldrDyldModUnmap(PKLDRDYLDMOD pMod); 314 int kldrDyldModLoadPrerequisites(PKLDRDYLDMOD pMod, const char *psz Name, const char *pszDefPrefix, const char *pszDefSuffix,329 int kldrDyldModLoadPrerequisites(PKLDRDYLDMOD pMod, const char *pszDefPrefix, const char *pszDefSuffix, 315 330 KLDRDYLDSEARCH enmSearch, unsigned fFlags); 316 331 int kldrDyldModCheckPrerequisites(PKLDRDYLDMOD pMod); … … 333 348 334 349 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.) */ 352 extern PKLDRDYLDMOD kLdrDyldHead; 353 /** Pointer to the tail module. 354 * (This is exported, so no prefix.) */ 355 extern PKLDRDYLDMOD kLdrDyldTail; 339 356 /** Pointer to the head module of the termination order list. */ 340 357 extern PKLDRDYLDMOD g_pkLdrDyldTermHead; -
trunk/kLdr/tg/KLDRSTATE.txvstc
r2840 r2842 463 463 </link> 464 464 <link uin="id83t9setug73fpetug74ah.nodeidswftetug73fpetugfwd3.linkid7ockpetuqdc66etuqdq4c"> 465 <property name="$metaclass" value="Transition"/>466 465 <participant role="Supplier" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeid8048etug73fpetugfpwv"/> 467 466 <participant role="Client" referencedUin="design:node:::id83t9setug73fpetug74ah.nodeidswftetug73fpetugfwd3"/> 467 <property name="$metaclass" value="Transition"/> 468 468 <property name="$event_name" value="Loaded again"/> 469 469 </link> -
trunk/kLdr/tg/kLdr.tpr
r2840 r2842 14 14 Developer.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}} 15 15 Developer.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}}16 Developer.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}} 17 17 names.Developer={kLdr,DesignWorkspace,CodingWorkspace,DebugWorkspace} 18 18 [vcs]
Note:
See TracChangeset
for help on using the changeset viewer.