VirtualBox

Changeset 3313 in kBuild for trunk


Ignore:
Timestamp:
Mar 16, 2020 2:31:38 AM (5 years ago)
Author:
bird
Message:

kmk,kWorker: Assign processor groups to kWorker processes. Added --special-env hack for having a mspdbsrv.exe instance per processor group (using _MSPDBSRV_ENDPOINT_). This was complicated by PCH requiring to share .pdb file and therefore mspdbsrv.exe instance, requiring a mspdb100.dll re-init hack to disconnect kWorker from the previous mspdbsrv when switching. fun.

Location:
trunk
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/kBuild/tools/VCC100AMD64.kmk

    r3303 r3313  
    8080  ifneq ($(substr $(PATH_TOOL_VCC100AMD64_BIN),-9),x86_amd64)
    8181   TOOL_VCC100AMD64_KSUBMIT ?= kmk_builtin_kSubmit --64-bit
    82    TOOL_VCC100AMD64_KSUBMIT_DD = $(TOOL_VCC100AMD64_KSUBMIT) --
     82   if $(KBUILD_KMK_REVISION) > 3311
     83    TOOL_VCC100AMD64_KSUBMIT_SPECIAL_ENV = -s "_MSPDBSRV_ENDPOINT_=kBuild_vcc10_amd64_@@AUTHENTICATION_ID@@_$(if-expr defined($(target)_1_VCC_COMMON_OBJ_PDB),common,@@PROCESS_GROUP@@)"
     84   endif
     85   TOOL_VCC100AMD64_KSUBMIT_DD = $(TOOL_VCC100AMD64_KSUBMIT) $(TOOL_VCC100AMD64_KSUBMIT_SPECIAL_ENV) --
    8386  else
    8487   # "fatal error C1902: Program database manager mismatch; please check your installation" when mixing with the 32-bit compiler.
     
    162165 TOOL_VCC100AMD64_COMPILE_C_DONT_PURGE_OUTPUT := 1 # speed
    163166 define TOOL_VCC100AMD64_COMPILE_C_CMDS
    164         $(QUIET)$(TOOL_VCC100AMD64_KSUBMIT) -P $(DEP_OBJ_INT) -f -s -q -o $(dep) -t $(obj) $(obj)\
     167        $(QUIET)$(TOOL_VCC100AMD64_KSUBMIT) $(TOOL_VCC100AMD64_KSUBMIT_SPECIAL_ENV) \
     168                -P $(DEP_OBJ_INT) -f -s -q -o $(dep) -t $(obj) $(obj)\
    165169                -- $(TOOL_VCC100AMD64_CC) -c\
    166170                $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\
     
    202206 TOOL_VCC100AMD64_COMPILE_CXX_DONT_PURGE_OUTPUT := 1 # speed
    203207 define TOOL_VCC100AMD64_COMPILE_CXX_CMDS
    204         $(QUIET)$(TOOL_VCC100AMD64_KSUBMIT) -P $(DEP_OBJ_INT) -f -s -q -o $(dep) -t $(obj) $(obj)\
    205                 -- $(TOOL_VCC100AMD64_CXX) -c\
     208        $(QUIET)$(TOOL_VCC100AMD64_KSUBMIT) $(TOOL_VCC100AMD64_KSUBMIT_SPECIAL_ENV) \
     209                -P $(DEP_OBJ_INT) -f -s -q -o $(dep) -t $(obj) $(obj) -- $(TOOL_VCC100AMD64_CXX) -c\
    206210                $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\
    207211                $(if-expr defined($(target)_PCH_HDR)\
     
    246250 define TOOL_VCC100AMD64-PCH_COMPILE_CXX_CMDS
    247251        $(QUIET)$(RM) -f -- $($(target)_1_VCC_PCH_FILE) $($(target)_1_VCC_COMMON_OBJ_PDB)
    248         $(QUIET)$(TOOL_VCC100AMD64_KSUBMIT) --no-pch-caching -P $(DEP_OBJ_INT) -f -s -q -e .pch -o $(dep) -t $(obj) $(obj)\
     252        $(QUIET)$(TOOL_VCC100AMD64_KSUBMIT) --no-pch-caching $(TOOL_VCC100AMD64_KSUBMIT_SPECIAL_ENV) \
     253                -P $(DEP_OBJ_INT) -f -s -q -e .pch -o $(dep) -t $(obj) $(obj)\
    249254                -- $(TOOL_VCC100AMD64_CXX) -c -Yc\
    250255                $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\
  • trunk/kBuild/tools/VCC100X86.kmk

    r3303 r3313  
    7878 ifeq ($(KBUILD_HOST),win)
    7979  TOOL_VCC100X86_KSUBMIT ?= kmk_builtin_kSubmit --32-bit
    80   TOOL_VCC100X86_KSUBMIT_DD = $(TOOL_VCC100X86_KSUBMIT) --
     80  if $(KBUILD_KMK_REVISION) > 3311
     81   TOOL_VCC100X86_KSUBMIT_SPECIAL_ENV = -s "_MSPDBSRV_ENDPOINT_=kBuild_vcc10_x86_@@AUTHENTICATION_ID@@_$(if-expr defined($(target)_1_VCC_COMMON_OBJ_PDB),common,@@PROCESS_GROUP@@)"
     82  endif
     83  TOOL_VCC100X86_KSUBMIT_DD = $(TOOL_VCC100X86_KSUBMIT) $(TOOL_VCC100X86_KSUBMIT_SPECIAL_ENV) --
    8184 endif
    8285endif
     
    155158 TOOL_VCC100X86_COMPILE_C_DONT_PURGE_OUTPUT = 1 # speed
    156159 define TOOL_VCC100X86_COMPILE_C_CMDS
    157         $(QUIET)$(TOOL_VCC100X86_KSUBMIT) -P $(DEP_OBJ_INT) -f -s -q -o $(dep) -t $(obj) $(obj)\
     160        $(QUIET)$(TOOL_VCC100X86_KSUBMIT) $(TOOL_VCC100X86_KSUBMIT_SPECIAL_ENV) \
     161                -P $(DEP_OBJ_INT) -f -s -q -o $(dep) -t $(obj) $(obj)\
    158162                -- $(TOOL_VCC100X86_CC) -c\
    159163                $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\
     
    195199 TOOL_VCC100X86_COMPILE_CXX_DONT_PURGE_OUTPUT = 1 # speed
    196200 define TOOL_VCC100X86_COMPILE_CXX_CMDS
    197         $(QUIET)$(TOOL_VCC100X86_KSUBMIT) -P $(DEP_OBJ_INT) -f -s -q -o $(dep) -t $(obj) $(obj)\
     201        $(QUIET)$(TOOL_VCC100X86_KSUBMIT) $(TOOL_VCC100X86_KSUBMIT_SPECIAL_ENV) \
     202                -P $(DEP_OBJ_INT) -f -s -q -o $(dep) -t $(obj) $(obj)\
    198203                -- $(TOOL_VCC100X86_CXX) -c\
    199204                $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\
     
    238243ifdef TOOL_VCC100X86_KSUBMIT
    239244 define TOOL_VCC100X86-PCH_COMPILE_CXX_CMDS
    240         $(QUIET)$(TOOL_VCC100X86_KSUBMIT) --no-pch-caching -P $(DEP_OBJ_INT) -f -s -q -e .pch -o $(dep) -t $(obj) $(obj)\
     245        $(RM) -f -- "$($(target)_1_VCC_COMMON_OBJ_PDB)"
     246        $(QUIET)$(TOOL_VCC100X86_KSUBMIT) --no-pch-caching $(TOOL_VCC100X86_KSUBMIT_SPECIAL_ENV) \
     247                -P $(DEP_OBJ_INT) -f -s -q -e .pch -o $(dep) -t $(obj) $(obj)\
    241248                -- $(TOOL_VCC100X86_CXX) -c -Yc\
    242249                $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\
     
    257264                $(subst /,\\,$(abspath $(source)))
    258265        $(QUIET)$(DEP_OBJ) -f -s -q  -e .pch -o $(dep) -t $(obj) $(obj)
    259 
    260266 endef
    261267endif # !TOOL_VCC100X86_KSUBMIT
  • trunk/src/kWorker/kWorker.c

    r3200 r3313  
    195195
    196196
     197/**
     198 * Generate CRT slot wrapper functions.
     199 */
     200#define CRT_SLOT_FUNCTION_WRAPPER(a_RetTypeAndCallConv, a_FnName, a_aArgsDecl, a_aArgCall) \
     201    static a_RetTypeAndCallConv a_FnName##00 a_aArgsDecl { const unsigned iCrtSlot =  0; return a_FnName##_wrapped a_aArgCall; } \
     202    static a_RetTypeAndCallConv a_FnName##01 a_aArgsDecl { const unsigned iCrtSlot =  1; return a_FnName##_wrapped a_aArgCall; } \
     203    static a_RetTypeAndCallConv a_FnName##02 a_aArgsDecl { const unsigned iCrtSlot =  2; return a_FnName##_wrapped a_aArgCall; } \
     204    static a_RetTypeAndCallConv a_FnName##03 a_aArgsDecl { const unsigned iCrtSlot =  3; return a_FnName##_wrapped a_aArgCall; } \
     205    static a_RetTypeAndCallConv a_FnName##04 a_aArgsDecl { const unsigned iCrtSlot =  4; return a_FnName##_wrapped a_aArgCall; } \
     206    static a_RetTypeAndCallConv a_FnName##05 a_aArgsDecl { const unsigned iCrtSlot =  5; return a_FnName##_wrapped a_aArgCall; } \
     207    static a_RetTypeAndCallConv a_FnName##06 a_aArgsDecl { const unsigned iCrtSlot =  6; return a_FnName##_wrapped a_aArgCall; } \
     208    static a_RetTypeAndCallConv a_FnName##07 a_aArgsDecl { const unsigned iCrtSlot =  7; return a_FnName##_wrapped a_aArgCall; } \
     209    static a_RetTypeAndCallConv a_FnName##08 a_aArgsDecl { const unsigned iCrtSlot =  8; return a_FnName##_wrapped a_aArgCall; } \
     210    static a_RetTypeAndCallConv a_FnName##09 a_aArgsDecl { const unsigned iCrtSlot =  9; return a_FnName##_wrapped a_aArgCall; } \
     211    static a_RetTypeAndCallConv a_FnName##10 a_aArgsDecl { const unsigned iCrtSlot = 10; return a_FnName##_wrapped a_aArgCall; } \
     212    static a_RetTypeAndCallConv a_FnName##11 a_aArgsDecl { const unsigned iCrtSlot = 11; return a_FnName##_wrapped a_aArgCall; } \
     213    static a_RetTypeAndCallConv a_FnName##12 a_aArgsDecl { const unsigned iCrtSlot = 12; return a_FnName##_wrapped a_aArgCall; } \
     214    static a_RetTypeAndCallConv a_FnName##13 a_aArgsDecl { const unsigned iCrtSlot = 13; return a_FnName##_wrapped a_aArgCall; } \
     215    static a_RetTypeAndCallConv a_FnName##14 a_aArgsDecl { const unsigned iCrtSlot = 14; return a_FnName##_wrapped a_aArgCall; } \
     216    static a_RetTypeAndCallConv a_FnName##15 a_aArgsDecl { const unsigned iCrtSlot = 15; return a_FnName##_wrapped a_aArgCall; } \
     217    static a_RetTypeAndCallConv a_FnName##16 a_aArgsDecl { const unsigned iCrtSlot = 16; return a_FnName##_wrapped a_aArgCall; } \
     218    static a_RetTypeAndCallConv a_FnName##17 a_aArgsDecl { const unsigned iCrtSlot = 17; return a_FnName##_wrapped a_aArgCall; } \
     219    static a_RetTypeAndCallConv a_FnName##18 a_aArgsDecl { const unsigned iCrtSlot = 18; return a_FnName##_wrapped a_aArgCall; } \
     220    static a_RetTypeAndCallConv a_FnName##19 a_aArgsDecl { const unsigned iCrtSlot = 19; return a_FnName##_wrapped a_aArgCall; } \
     221    static a_RetTypeAndCallConv a_FnName##20 a_aArgsDecl { const unsigned iCrtSlot = 20; return a_FnName##_wrapped a_aArgCall; } \
     222    static a_RetTypeAndCallConv a_FnName##21 a_aArgsDecl { const unsigned iCrtSlot = 21; return a_FnName##_wrapped a_aArgCall; } \
     223    static a_RetTypeAndCallConv a_FnName##22 a_aArgsDecl { const unsigned iCrtSlot = 22; return a_FnName##_wrapped a_aArgCall; } \
     224    static a_RetTypeAndCallConv a_FnName##23 a_aArgsDecl { const unsigned iCrtSlot = 23; return a_FnName##_wrapped a_aArgCall; } \
     225    static a_RetTypeAndCallConv a_FnName##24 a_aArgsDecl { const unsigned iCrtSlot = 24; return a_FnName##_wrapped a_aArgCall; } \
     226    static a_RetTypeAndCallConv a_FnName##25 a_aArgsDecl { const unsigned iCrtSlot = 25; return a_FnName##_wrapped a_aArgCall; } \
     227    static a_RetTypeAndCallConv a_FnName##26 a_aArgsDecl { const unsigned iCrtSlot = 26; return a_FnName##_wrapped a_aArgCall; } \
     228    static a_RetTypeAndCallConv a_FnName##27 a_aArgsDecl { const unsigned iCrtSlot = 27; return a_FnName##_wrapped a_aArgCall; } \
     229    static a_RetTypeAndCallConv a_FnName##28 a_aArgsDecl { const unsigned iCrtSlot = 28; return a_FnName##_wrapped a_aArgCall; } \
     230    static a_RetTypeAndCallConv a_FnName##29 a_aArgsDecl { const unsigned iCrtSlot = 29; return a_FnName##_wrapped a_aArgCall; } \
     231    static a_RetTypeAndCallConv a_FnName##30 a_aArgsDecl { const unsigned iCrtSlot = 30; return a_FnName##_wrapped a_aArgCall; } \
     232    static a_RetTypeAndCallConv a_FnName##31 a_aArgsDecl { const unsigned iCrtSlot = 31; return a_FnName##_wrapped a_aArgCall; } \
     233    static const KUPTR a_FnName[] = \
     234    { \
     235        (KUPTR)a_FnName##00, \
     236        (KUPTR)a_FnName##01, \
     237        (KUPTR)a_FnName##02, \
     238        (KUPTR)a_FnName##03, \
     239        (KUPTR)a_FnName##04, \
     240        (KUPTR)a_FnName##05, \
     241        (KUPTR)a_FnName##06, \
     242        (KUPTR)a_FnName##07, \
     243        (KUPTR)a_FnName##08, \
     244        (KUPTR)a_FnName##09, \
     245        (KUPTR)a_FnName##10, \
     246        (KUPTR)a_FnName##11, \
     247        (KUPTR)a_FnName##12, \
     248        (KUPTR)a_FnName##13, \
     249        (KUPTR)a_FnName##14, \
     250        (KUPTR)a_FnName##15, \
     251        (KUPTR)a_FnName##16, \
     252        (KUPTR)a_FnName##17, \
     253        (KUPTR)a_FnName##18, \
     254        (KUPTR)a_FnName##19, \
     255        (KUPTR)a_FnName##20, \
     256        (KUPTR)a_FnName##21, \
     257        (KUPTR)a_FnName##22, \
     258        (KUPTR)a_FnName##23, \
     259        (KUPTR)a_FnName##24, \
     260        (KUPTR)a_FnName##25, \
     261        (KUPTR)a_FnName##26, \
     262        (KUPTR)a_FnName##27, \
     263        (KUPTR)a_FnName##28, \
     264        (KUPTR)a_FnName##29, \
     265        (KUPTR)a_FnName##30, \
     266        (KUPTR)a_FnName##31, \
     267    }
     268
     269
    197270/*********************************************************************************************************************************
    198271*   Structures and Typedefs                                                                                                      *
     
    221294typedef struct KWMODULE
    222295{
    223     /** Pointer to the next image. */
    224     PKWMODULE           pNext;
     296    /** Pointer to the next image withe the same hash. */
     297    PKWMODULE           pNextHash;
     298    /** Pointer to the next image in the global list. */
     299    PKWMODULE           pNextList;
    225300    /** The normalized path to the image. */
    226301    const char         *pszPath;
     
    243318    /** The of the loaded image bits. */
    244319    KSIZE               cbImage;
     320    /** The CRT slot for this module, if applicable (KU8_MAX when not). */
     321    KU8                 iCrtSlot;
     322    /** Loop prevention when working the tree. */
     323    KBOOL               fVisited;
     324    /** HACK: Set if re-init is needed (fReInitOnMsPdbSrvEndpointChange). */
     325    KBOOL               fNeedReInit;
     326    /** HACK: Reinit when _MSPDBSRV_ENDPOINT_ changes, K_FALSE if not applicable.
     327     * 1 if applicable but not yet used, 2 if used and have pszMsPdbSrvEndpoint. */
     328    KU8                 fReInitOnMsPdbSrvEndpointChange;
     329    /** HACK: The old _MSPDBSRV_ENDPOINT_ value. */
     330    char               *pszMsPdbSrvEndpoint;
    245331
    246332    union
     
    851937} KWSANDBOX;
    852938
     939
     940/** A CRT slot.  */
     941typedef struct KWCRTSLOT
     942{
     943    KU32        iSlot;
     944
     945    /** The CRT module data.    */
     946    PKWMODULE   pModule;
     947    /** Pointer to the malloc function.   */
     948    void * (__cdecl *pfnMalloc)(size_t);
     949
     950} KWCRTSLOT;
     951typedef KWCRTSLOT *PKWCRTSLOT;
     952
     953
    853954/** Replacement function entry. */
    854955typedef struct KWREPLACEMENTFUNCTION
     
    860961    /** The module name (optional). */
    861962    const char *pszModule;
    862     /** The replacement function or data address. */
     963    /** The replacement function, data address or CRT slot function array. */
    863964    KUPTR       pfnReplacement;
    864965    /** Only replace in the executable.
    865966     * @todo fix the reinitialization of non-native DLLs!  */
    866967    KBOOL       fOnlyExe;
     968    /** Set if pfnReplacement points to a CRT slot function array. */
     969    KBOOL       fCrtSlotArray;
    867970} KWREPLACEMENTFUNCTION;
    868971typedef KWREPLACEMENTFUNCTION const *PCKWREPLACEMENTFUNCTION;
     
    884987#endif
    885988
     989/**
     990 * One test job (--full-test).
     991 */
     992typedef struct KWONETEST
     993{
     994    /** Where this job originated. */
     995    const char     *pszJobSrc;
     996    /** The argument number it started with. */
     997    unsigned        iJobSrc;
     998    /** Set if virgin, clear if modified. */
     999    KBOOL           fVirgin;
     1000
     1001    /** Number of runs to give it. */
     1002    unsigned        cRuns;
     1003
     1004    /** @name kSubmitHandleJobUnpacked arguments
     1005     * @{ */
     1006    const char     *pszExecutable;
     1007    const char     *pszCwd;
     1008    KU32            cArgs;
     1009    const char    **papszArgs;
     1010    KU32            cEnvVars;
     1011    const char    **papszEnvVars;
     1012    const char     *pszSpecialEnv;
     1013    KBOOL           fWatcomBrainDamange;
     1014    KBOOL           fNoPchCaching;
     1015    KU32            cPostCmdArgs;
     1016    const char    **papszPostCmdArgs;
     1017    /** @} */
     1018
     1019    /** Pointer to the next one. */
     1020    struct KWONETEST *pNext;
     1021} KWONETEST;
     1022/** Pointer to one test job. */
     1023typedef KWONETEST *PKWONETEST;
     1024
    8861025
    8871026/*********************************************************************************************************************************
     
    8971036static PKWMODULE    g_pModPrevInLdBuf = NULL;
    8981037
     1038/** Module list head. */
     1039static PKWMODULE    g_pModuleHead = NULL;
     1040/** Where to insert the next module. */
     1041static PKWMODULE   *g_ppModuleNext = &g_pModuleHead;
     1042
    8991043/** Module hash table. */
    9001044static PKWMODULE    g_apModules[127];
     
    9111055static PKWMODULE    g_pModPendingTlsAlloc = NULL;
    9121056
     1057/** CRT slots.
     1058 * @note The number of entires here must match CRT_SLOT_FUNCTION_WRAPPER. */
     1059static KWCRTSLOT    g_aCrtSlots[32];
    9131060
    9141061/** The file system cache. */
     
    9261073/** Whether we should restart the worker. */
    9271074static KBOOL        g_fRestart = K_FALSE;
     1075
     1076/** The process group this worker is tied to (--group option), -1 if none. */
     1077static KI32         g_iProcessGroup = -1;
    9281078
    9291079/** Whether control-C/SIGINT or Control-Break/SIGBREAK have been seen. */
     
    10461196static int kwLdrModuleResolveAndLookup(const char *pszName, PKWMODULE pExe, PKWMODULE pImporter,
    10471197                                       const char *pszSearchPath, PKWMODULE *ppMod);
     1198static PKWMODULE kwLdrModuleForLoadedNative(const char *pszName, KBOOL fEnsureCrtSlot);
     1199static char *kwSandboxDoGetEnvA(PKWSANDBOX pSandbox, const char *pchVar, KSIZE cchVar);
    10481200static KBOOL kwSandboxHandleTableEnter(PKWSANDBOX pSandbox, PKWHANDLE pHandle, HANDLE hHandle);
    10491201#ifdef WITH_CONSOLE_OUTPUT_BUFFERING
     
    11601312    fprintf(stderr, "kWorker: error: ");
    11611313    vfprintf(stderr, pszFormat, va);
     1314    fflush(stderr); /* In case it's a pipe. */
    11621315
    11631316    SetLastError(dwSavedErr);
     
    16241777    if (--pMod->cRefs == 0)
    16251778    {
    1626         /* Unlink it. */
     1779        /* Unlink it from the hash table. */
    16271780        if (!pMod->fExe)
    16281781        {
     
    16301783            unsigned  idx   = pMod->uHashPath % K_ELEMENTS(g_apModules);
    16311784            if (g_apModules[idx] == pMod)
    1632                 g_apModules[idx] = pMod->pNext;
     1785                g_apModules[idx] = pMod->pNextHash;
    16331786            else
    16341787            {
    16351788                PKWMODULE pPrev = g_apModules[idx];
    16361789                kHlpAssert(pPrev != NULL);
    1637                 while (pPrev->pNext != pMod)
     1790                while (pPrev->pNextHash != pMod)
    16381791                {
    1639                     pPrev = pPrev->pNext;
     1792                    pPrev = pPrev->pNextHash;
    16401793                    kHlpAssert(pPrev != NULL);
    16411794                }
    1642                 pPrev->pNext = pMod->pNext;
    1643             }
     1795                pPrev->pNextHash = pMod->pNextHash;
     1796            }
     1797        }
     1798
     1799        /* Unlink it from the list. */
     1800        if (pMod != g_pModuleHead)
     1801        {
     1802            PKWMODULE pPrev = g_pModuleHead;
     1803            while (pPrev)
     1804            {
     1805                if (pPrev->pNextList == pMod)
     1806                {
     1807                    pPrev->pNextList = pMod->pNextList;
     1808                    if (!pMod->pNextList)
     1809                        g_ppModuleNext = &pPrev->pNextList;
     1810                    break;
     1811                }
     1812                pPrev = pPrev->pNextList;
     1813            }
     1814            kHlpAssert(pPrev != NULL);
     1815        }
     1816        else
     1817        {
     1818            g_pModuleHead = pMod->pNextList;
     1819            if (!pMod->pNextList)
     1820                g_ppModuleNext = &g_pModuleHead;
    16441821        }
    16451822
     
    16661843        }
    16671844
     1845        if (pMod->iCrtSlot != KU8_MAX)
     1846            g_aCrtSlots[pMod->iCrtSlot].pModule = NULL;
     1847
     1848        if (pMod->pszMsPdbSrvEndpoint)
     1849        {
     1850            kHlpFree(pMod->pszMsPdbSrvEndpoint);
     1851            pMod->pszMsPdbSrvEndpoint = NULL;
     1852        }
     1853
    16681854        kHlpFree(pMod);
    16691855    }
     
    16811867static PKWMODULE kwLdrModuleLink(PKWMODULE pMod)
    16821868{
    1683     unsigned idx = pMod->uHashPath % K_ELEMENTS(g_apModules);
    1684     pMod->pNext = g_apModules[idx];
    1685     g_apModules[idx] = pMod;
     1869    if (!pMod->fExe)
     1870    {
     1871        unsigned idx = pMod->uHashPath % K_ELEMENTS(g_apModules);
     1872        pMod->pNextHash = g_apModules[idx];
     1873        g_apModules[idx] = pMod;
     1874    }
     1875
     1876    pMod->pNextList = NULL;
     1877    *g_ppModuleNext = pMod;
     1878    g_ppModuleNext = &pMod->pNextList;
     1879
    16861880    return pMod;
    16871881}
     
    17481942            KU32                iThunk;
    17491943            const char * const  pszImport   = (const char *)&pbImage[pImpDesc->Name];
     1944            PKWMODULE           pImportMod  = NULL;
    17501945            PIMAGE_THUNK_DATA   paThunks    = (PIMAGE_THUNK_DATA)&pbImage[pImpDesc->FirstThunk];
    17511946            PIMAGE_THUNK_DATA   paOrgThunks = (PIMAGE_THUNK_DATA)&pbImage[pImpDesc->OriginalFirstThunk];
     
    18182013                                }
    18192014
    1820                                 paThunks[iThunk].u1.AddressOfData = g_aSandboxNativeReplacements[i].pfnReplacement;
     2015                                /*
     2016                                 * Unslotted replacements are simple.
     2017                                 */
     2018                                if (!g_aSandboxNativeReplacements[i].fCrtSlotArray)
     2019                                    paThunks[iThunk].u1.AddressOfData = g_aSandboxNativeReplacements[i].pfnReplacement;
     2020                                else
     2021                                {
     2022                                    /*
     2023                                     * Must find our module entry for this module, possibly creating one.
     2024                                     */
     2025                                    if (!pImportMod)
     2026                                    {
     2027                                        pImportMod = kwLdrModuleForLoadedNative(pszImport, K_TRUE /*fEnsureCrtSlot*/);
     2028                                        if (!pImportMod)
     2029                                        {
     2030                                            kwErrPrintf("Failed to get module '%s' when performing replacements on module '%s'!\n",
     2031                                                        pszImport, pMod->pszPath);
     2032                                            break;
     2033                                        }
     2034                                    }
     2035                                    paThunks[iThunk].u1.AddressOfData
     2036                                        = ((KUPTR *)g_aSandboxNativeReplacements[i].pfnReplacement)[pImportMod->iCrtSlot];
     2037                                }
    18212038                                break;
    18222039                            }
     
    18592076     * Create the entry.
    18602077     */
    1861     PKWMODULE pMod   = (PKWMODULE)kHlpAllocZ(sizeof(*pMod) + cbPath + cbPath * 2 * sizeof(wchar_t));
     2078    PKWMODULE pMod = (PKWMODULE)kHlpAllocZ(sizeof(*pMod) + cbPath + cbPath * 2 * sizeof(wchar_t));
    18622079    if (pMod)
    18632080    {
     
    18732090        pMod->hOurMod       = (HMODULE)(KUPTR)pLdrMod->aSegments[0].MapAddress;
    18742091        pMod->cbImage       = (KSIZE)kLdrModSize(pLdrMod);
     2092        pMod->iCrtSlot      = KU8_MAX;
     2093        pMod->fNeedReInit   = K_FALSE;
     2094        pMod->pszMsPdbSrvEndpoint = NULL;
     2095        pMod->fReInitOnMsPdbSrvEndpointChange = kHlpStrNICompAscii(&pMod->pszPath[pMod->offFilename], TUPLE("mspdb")) == 0;
    18752096
    18762097        if (fDoReplacements)
     
    19062127     */
    19072128    PKLDRMOD pLdrMod;
    1908     int rc = kLdrModOpenNative(pszPath, &pLdrMod);
     2129    int rc = kLdrModOpenNative(pszPath, KLDRMOD_OPEN_FLAGS_NATIVE_ALLOW_INIT_TERM, &pLdrMod);
    19092130    if (rc == 0)
    19102131    {
     
    22672488                    pMod->fNative       = K_FALSE;
    22682489                    pMod->pLdrMod       = pLdrMod;
    2269                     pMod->u.Manual.cImpMods = (KU32)cImports;
     2490                    pMod->iCrtSlot      = KU8_MAX;
     2491                    pMod->fNeedReInit   = K_FALSE;
     2492                    pMod->fReInitOnMsPdbSrvEndpointChange = K_FALSE;
     2493                    pMod->pszMsPdbSrvEndpoint       = NULL;
     2494                    pMod->u.Manual.cImpMods         = (KU32)cImports;
    22702495#if defined(KBUILD_OS_WINDOWS) && defined(KBUILD_ARCH_AMD64)
    22712496                    pMod->u.Manual.fRegisteredFunctionTable = K_FALSE;
     
    23102535                             */
    23112536                            pMod->hOurMod = (HMODULE)pMod->u.Manual.pbLoad;
    2312                             if (!fExe)
    2313                                 kwLdrModuleLink(pMod);
     2537                            kwLdrModuleLink(pMod);
    23142538                            KW_LOG(("New module: %p LB %#010x %s (kLdr)\n",
    23152539                                    pMod->u.Manual.pbLoad, pMod->cbImage, pMod->pszPath));
     
    26462870                        && kHlpStrComp(pMod->pszPath, szNormPath) == 0)
    26472871                        return kwLdrModuleRetain(pMod);
    2648                     pMod = pMod->pNext;
     2872                    pMod = pMod->pNextHash;
    26492873                } while (pMod);
    26502874            }
     
    27763000    *ppMod = NULL;
    27773001    return KERR_GENERAL_FAILURE;
     3002}
     3003
     3004
     3005/**
     3006 * Creates a CRT slot for the given module.
     3007 *
     3008 * @returns 0 on success, non-zero on failure.
     3009 * @param   pModule             The module.
     3010 */
     3011static int kwLdrModuleCreateCrtSlot(PKWMODULE pModule)
     3012{
     3013    KSIZE iSlot;
     3014    kHlpAssert(pModule->iCrtSlot == KU8_MAX);
     3015    for (iSlot = 0; iSlot < K_ELEMENTS(g_aCrtSlots); iSlot++)
     3016        if (g_aCrtSlots[iSlot].pModule == NULL)
     3017        {
     3018            KLDRADDR uAddr;
     3019            int rc;
     3020
     3021            /* Do the linking: */
     3022            g_aCrtSlots[iSlot].pModule = pModule;
     3023            g_aCrtSlots[iSlot].iSlot   = (KU32)iSlot;
     3024            pModule->iCrtSlot          = (KU8)iSlot;
     3025
     3026            /* resolve symbols: */
     3027            rc = kLdrModQuerySymbol(pModule->pLdrMod, NULL /*pvBits*/, KLDRMOD_BASEADDRESS_MAP, KU32_MAX, "malloc", 6,
     3028                                    NULL /*pvszVersion*/, NULL /*pfnGetForwarder*/, NULL /*pvUser*/, &uAddr, NULL);
     3029            *(KUPTR *)&g_aCrtSlots[iSlot].pfnMalloc = rc == 0 ? (KUPTR)uAddr : 0;
     3030            if (rc != 0)
     3031                kwErrPrintf("Failed to resolved 'malloc' in '%s': %d\n", pModule->pszPath, rc);
     3032
     3033            return 0;
     3034        }
     3035    kwErrPrintf("Out of CRT slots!\n");
     3036    return KERR_NO_MEMORY;
     3037}
     3038
     3039
     3040/**
     3041 * Locates the module structure for an already loaded native module.
     3042 *
     3043 * This will create a module structure if needed.
     3044 *
     3045 * @returns Pointer to the module structure on success, NULL on failure.
     3046 * @param   pszName         The name of the module.
     3047 * @param   fEnsureCrtSlot  Whether to ensure that it has a valid CRT slot.
     3048 */
     3049static PKWMODULE kwLdrModuleForLoadedNative(const char *pszName, KBOOL fEnsureCrtSlot)
     3050{
     3051    /*
     3052     * Locate the module and get a normalized path for it.
     3053     */
     3054    HANDLE hModule = GetModuleHandleA(pszName);
     3055    if (hModule)
     3056    {
     3057        char szModPath[1024];
     3058        if (GetModuleFileNameA(hModule, szModPath, sizeof(szModPath)) > 0)
     3059        {
     3060            char szNormPath[1024];
     3061            int rc = kwPathNormalize(szModPath, szNormPath, sizeof(szNormPath));
     3062            if (rc == 0)
     3063            {
     3064                /*
     3065                 * Hash the path and look it up.
     3066                 */
     3067                KU32        uHashPath;
     3068                KSIZE const cchPath   = kwStrHashEx(szNormPath, &uHashPath);
     3069                unsigned    idxHash   = uHashPath % K_ELEMENTS(g_apModules);
     3070                PKWMODULE   pMod      = g_apModules[idxHash];
     3071                if (pMod)
     3072                {
     3073                    do
     3074                    {
     3075                        if (   pMod->uHashPath == uHashPath
     3076                            && kHlpStrComp(pMod->pszPath, szNormPath) == 0)
     3077                        {
     3078                            kwLdrModuleRetain(pMod);
     3079                            break;
     3080                        }
     3081                        pMod = pMod->pNextHash;
     3082                    } while (pMod);
     3083                }
     3084
     3085                /*
     3086                 * If not in the hash table, so create a module entry.
     3087                 */
     3088                if (!pMod)
     3089                {
     3090                    PKLDRMOD pLdrMod;
     3091                    rc = kLdrModOpenNativeByHandle((KUPTR)hModule, KLDRMOD_OPEN_FLAGS_NATIVE_ALLOW_INIT_TERM, &pLdrMod);
     3092                    if (rc == 0)
     3093                    {
     3094                        pMod = kwLdrModuleCreateForNativekLdrModule(pLdrMod, szNormPath, cchPath + 1, uHashPath,
     3095                                                                    K_FALSE /*fDoReplacements*/);
     3096                        if (!pMod)
     3097                        {
     3098                            kLdrModClose(pLdrMod);
     3099                            kwErrPrintf("out of memory\n");
     3100                        }
     3101                    }
     3102                    else
     3103                        kwErrPrintf("kLdrModOpenNativeByHandle failed for %p / '%s': %d\n", hModule, pszName, rc);
     3104                }
     3105                if (pMod)
     3106                {
     3107                    /*
     3108                     * Create a CRT slot for the module if necessary.
     3109                     */
     3110                    if (!fEnsureCrtSlot || pMod->iCrtSlot != KU8_MAX)
     3111                        return pMod;
     3112                    rc = kwLdrModuleCreateCrtSlot(pMod);
     3113                    if (rc == 0)
     3114                        return pMod;
     3115                    kwLdrModuleRelease(pMod);
     3116                }
     3117            }
     3118            else
     3119                kwErrPrintf("kwPathNormalize failed for '%s' (%s): %u!\n", szModPath, pszName, GetLastError());
     3120        }
     3121        else
     3122            kwErrPrintf("GetModuleFileNameA failed for '%s': %u!\n", pszName, GetLastError());
     3123    }
     3124    else
     3125        kwErrPrintf("Module '%s' was not found by GetModuleHandleA!\n", pszName);
     3126    return NULL;
    27783127}
    27793128
     
    29423291                pMod->u.Manual.enmState = KWMODSTATE_INIT_FAILED;
    29433292        }
     3293    }
     3294    /*
     3295     * Special hack to disconnect mspdbXXX.dll from mspdbsrv.exe when
     3296     * _MSPDBSRV_ENDPOINT_ changes value.
     3297     */
     3298    else if (pMod->fNeedReInit)
     3299    {
     3300        int rc2;
     3301        KWLDR_LOG(("kwLdrModuleInitTree: mspdb re-init hack: %s\n", pMod->pszPath));
     3302        //fprintf(stderr, "%d: kwLdrModuleInitTree: mspdb re-init hack: %s\n", getpid(), kwSandboxDoGetEnvA(&g_Sandbox, TUPLE("_MSPDBSRV_ENDPOINT_"))); fflush(stderr);
     3303        rc = kLdrModCallTerm(pMod->pLdrMod, pMod->u.Manual.pbLoad, (KUPTR)pMod->hOurMod);
     3304        rc2 = kLdrModCallInit(pMod->pLdrMod, pMod->u.Manual.pbLoad, (KUPTR)pMod->hOurMod);
     3305        if (!rc && !rc2)
     3306        { /* likely */ }
     3307        else
     3308        {
     3309            kwErrPrintf("Re-init of '%s' failed: rc=%d rc2=%d\n", pMod->pszPath, rc, rc2);
     3310            if (rc2 && !rc)
     3311                rc = rc2;
     3312        }
     3313        pMod->fNeedReInit = K_FALSE;
    29443314    }
    29453315    return rc;
     
    45864956
    45874957
     4958/** CRT - _wdupenv_s() (see _tdupenv_s(). */
     4959static errno_t __cdecl kwSandbox_msvcrt__wdupenv_s_wrapped(wchar_t **ppwszValue, size_t *pcwcValue, const wchar_t *pwszVarName,
     4960                                                           PKWCRTSLOT pSlot)
     4961{
     4962    errno_t rc;
     4963    wchar_t *pwszValue;
     4964    kHlpAssert(GetCurrentThreadId() == g_Sandbox.idMainThread);
     4965
     4966    if (ppwszValue)
     4967    {
     4968        pwszValue = kwSandboxDoGetEnvW(&g_Sandbox, pwszVarName, wcslen(pwszVarName));
     4969        if (pwszValue)
     4970        {
     4971            size_t cwcValue = wcslen(pwszValue);
     4972            wchar_t *pwszDst = pSlot->pfnMalloc ? (wchar_t *)pSlot->pfnMalloc((cwcValue + 1) * sizeof(wchar_t)) : NULL;
     4973            if (pwszDst)
     4974            {
     4975                memcpy(pwszDst, pwszValue, cwcValue * sizeof(wchar_t));
     4976                pwszDst[cwcValue] = '\0';
     4977                *ppwszValue = pwszDst;
     4978                if (pcwcValue)
     4979                    *pcwcValue = cwcValue;
     4980                rc = 0;
     4981            }
     4982            else
     4983            {
     4984                *ppwszValue = NULL;
     4985                if (pcwcValue)
     4986                    *pcwcValue  = 0;
     4987                rc = ENOMEM;
     4988            }
     4989        }
     4990        else
     4991        {
     4992            *ppwszValue = NULL;
     4993            if (pcwcValue)
     4994                *pcwcValue = 0;
     4995            rc = 0;
     4996        }
     4997        KW_LOG(("_wdupenv_s(,,%ls) -> %d '%ls'\n", pwszVarName, rc, *ppwszValue ? *ppwszValue : L"<null>"));
     4998        //fprintf(stderr, "%d: _wdupenv_s(,,%ls) -> %d '%ls'\n", getpid(), pwszVarName, rc, *ppwszValue ? *ppwszValue : L"<null>"); fflush(stderr); // HACKING
     4999    }
     5000    else
     5001    {
     5002        /*
     5003         * Warning! If mspdb100.dll ends up here, it won't reinitialize the event name
     5004         *          and continue to use the one it constructed when _MSPDBSRV_ENDPOINT_
     5005         *          was set to a value.
     5006         */
     5007        if (pcwcValue)
     5008            *pcwcValue = 0;
     5009        rc = EINVAL;
     5010        KW_LOG(("_wdupenv_s(,,%ls) -> EINVAL\n", pwszVarName));
     5011        //fprintf(stderr, "%d: _wdupenv_s(,,%ls) -> EINVAL\n", getpid(), pwszVarName); fflush(stderr); // HACKING
     5012    }
     5013    return rc;
     5014}
     5015CRT_SLOT_FUNCTION_WRAPPER(errno_t __cdecl, kwSandbox_msvcrt__wdupenv_s,
     5016                          (wchar_t **ppwszValue, size_t *pcwcValue, const wchar_t *pwszVarName),
     5017                          (ppwszValue, pcwcValue, pwszVarName, &g_aCrtSlots[iCrtSlot]));
     5018
     5019
    45885020
    45895021/*
     
    46655097                return pDynLoad->hmod;
    46665098            }
    4667             pMod = pMod->pNext;
     5099            pMod = pMod->pNextHash;
    46685100        } while (pMod);
    46695101    }
     
    46775109    {
    46785110        PKLDRMOD pLdrMod;
    4679         int rc = kLdrModOpenNativeByHandle((KUPTR)hmod, &pLdrMod);
     5111        int rc = kLdrModOpenNativeByHandle((KUPTR)hmod, KLDRMOD_OPEN_FLAGS_NATIVE_ALLOW_INIT_TERM, &pLdrMod);
    46805112        if (rc == 0)
    46815113        {
     
    77908222
    77918223    /*
    7792      * Flush the two line buffer, the the combined buffer.
     8224     * Flush the two line buffer, then the combined buffer.
    77938225     */
    77948226    kwSandboxConsoleFinalFlushLineBuf(pSandbox, &pSandbox->StdErr, "StdErr");
     
    95089940    { TUPLE("_amsg_exit"),                  NULL,       (KUPTR)kwSandbox_msvcrt__amsg_exit },
    95099941    { TUPLE("terminate"),                   NULL,       (KUPTR)kwSandbox_msvcrt_terminate },
     9942    { TUPLE("_wdupenv_s"),                  NULL,       (KUPTR)kwSandbox_msvcrt__wdupenv_s, K_FALSE /*fOnlyExe*/, K_TRUE /*fCrtSlotArray*/ },
    95109943
    95119944#if 0 /* used by mspdbXXX.dll */
     
    960410037
    960510038/**
     10039 * Resets the KWMODULE::fVisited flag for _all_ known modules.
     10040 */
     10041static void kwSandboxResetModuleVisited(void)
     10042{
     10043    PKWMODULE pMod = g_pModuleHead;
     10044    while (pMod)
     10045    {
     10046        pMod->fVisited = K_FALSE;
     10047        pMod = pMod->pNextList;
     10048    }
     10049}
     10050
     10051
     10052/**
    960610053 * Used by kwSandboxExec to reset the state of the module tree.
    960710054 *
     
    961210059static void kwSandboxResetModuleState(PKWMODULE pMod)
    961310060{
    9614     if (   !pMod->fNative
    9615         && pMod->u.Manual.enmState != KWMODSTATE_NEEDS_BITS)
    9616     {
    9617         KSIZE iImp;
     10061    KWLDR_LOG(("kwSandboxResetModuleState: %d %d %s\n", pMod->fNative, pMod->fVisited, pMod->pszPath));
     10062    if (!pMod->fNative)
     10063    {
    961810064        pMod->u.Manual.enmState = KWMODSTATE_NEEDS_BITS;
    9619         iImp = pMod->u.Manual.cImpMods;
    9620         while (iImp-- > 0)
    9621             kwSandboxResetModuleState(pMod->u.Manual.apImpMods[iImp]);
     10065        if (!pMod->fVisited) /* Avoid loops. */
     10066        {
     10067            KSIZE iImp;
     10068            pMod->fVisited = K_TRUE;
     10069            iImp = pMod->u.Manual.cImpMods;
     10070            while (iImp-- > 0)
     10071                kwSandboxResetModuleState(pMod->u.Manual.apImpMods[iImp]);
     10072        }
     10073    }
     10074    /* Hack: Re-init mspdbXXX.dll when we want to use a different mspdbsrv.exe instance. */
     10075    else if (pMod->fReInitOnMsPdbSrvEndpointChange)
     10076    {
     10077        const char *pszValue = kwSandboxDoGetEnvA(&g_Sandbox, TUPLE("_MSPDBSRV_ENDPOINT_"));
     10078        if (pMod->fReInitOnMsPdbSrvEndpointChange == 1)
     10079        {
     10080            pMod->fReInitOnMsPdbSrvEndpointChange = 2;
     10081            pMod->pszMsPdbSrvEndpoint = pszValue ? kHlpStrDup(pszValue) : NULL;
     10082            KWLDR_LOG(("Not re-initing '%s': first time used (_MSPDBSRV_ENDPOINT_ is '%s')\n",
     10083                       pMod->pszPath, pszValue ? pszValue : "<null>"));
     10084        }
     10085        else if (   (pszValue == NULL && pMod->pszMsPdbSrvEndpoint == NULL)
     10086                 || (pszValue != NULL && pMod->pszMsPdbSrvEndpoint != NULL && kHlpStrComp(pszValue, pMod->pszMsPdbSrvEndpoint) == 0))
     10087            KWLDR_LOG(("Not re-initing '%s': _MSPDBSRV_ENDPOINT_ unchanged ('%s')\n",
     10088                       pMod->pszPath, pszValue ? pszValue : "<null>"));
     10089        else
     10090        {
     10091            KWLDR_LOG(("Re-initing '%s': _MSPDBSRV_ENDPOINT_ changed from '%s' to '%s'\n", pMod->pszPath,
     10092                       pMod->pszMsPdbSrvEndpoint ? pMod->pszMsPdbSrvEndpoint : "<null>", pszValue ? pszValue : "<null>"));
     10093            kHlpFree(pMod->pszMsPdbSrvEndpoint);
     10094            if (pszValue != NULL)
     10095                pMod->pszMsPdbSrvEndpoint = kHlpStrDup(pszValue);
     10096            else
     10097                pMod->pszMsPdbSrvEndpoint = NULL;
     10098            pMod->fNeedReInit = K_TRUE;
     10099        }
    962210100    }
    962310101}
     
    1020710685         * Do module initialization.
    1020810686         */
     10687        kwSandboxResetModuleVisited();
    1020910688        kwSandboxResetModuleState(pTool->u.Sandboxed.pExe);
    1021010689        rc = kwLdrModuleInitTree(pTool->u.Sandboxed.pExe);
     
    1029210771#endif
    1029310772        kwSandboxCleanup(&g_Sandbox);
     10773        /** @todo Flush sandboxed native CRTs too. */
    1029410774    }
    1029510775    else
     
    1032310803    }
    1032410804
    10325     return kwErrPrintfRc(42 + 5 , "Unknown post command: '%s'\n", pszCmd);
     10805    return kwErrPrintfRc(42 + 5, "Unknown post command: '%s'\n", pszCmd);
     10806}
     10807
     10808
     10809/**
     10810 * Helper for kSubmitHandleSpecialEnvVar that gets the current process group.
     10811 */
     10812static unsigned kwGetCurrentProcessorGroup(void)
     10813{
     10814    typedef BOOL (WINAPI *PFNGETTHREADGROUPAFFINITY)(HANDLE, GROUP_AFFINITY *);
     10815    HMODULE                   hmodKernel32 = GetModuleHandleW(L"KERNEL32.DLL");
     10816    PFNGETTHREADGROUPAFFINITY pfnGetter    = (PFNGETTHREADGROUPAFFINITY)GetProcAddress(hmodKernel32, "GetThreadGroupAffinity");
     10817    if (pfnGetter)
     10818    {
     10819        GROUP_AFFINITY GroupAffinity;
     10820        memset(&GroupAffinity, 0, sizeof(GroupAffinity));
     10821        if (pfnGetter(GetCurrentThread(), &GroupAffinity))
     10822            return GroupAffinity.Group;
     10823    }
     10824    return 0;
     10825}
     10826
     10827
     10828/**
     10829 * Helper for kSubmitHandleSpecialEnvVar that gets the current process group.
     10830 */
     10831static KSIZE kwGetCurrentAuthenticationIdAsString(char *pszValue)
     10832{
     10833    KSIZE  cchRet = 0;
     10834    HANDLE hToken;
     10835    if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
     10836    {
     10837        DWORD cbRet;
     10838        TOKEN_STATISTICS TokenStats;
     10839        memset(&TokenStats, 0, sizeof(TokenStats));
     10840        if (GetTokenInformation(hToken, TokenStatistics, &TokenStats, sizeof(TokenStats), &cbRet))
     10841            cchRet = sprintf(pszValue, "%" KX64_PRI,
     10842                             ((KU64)TokenStats.AuthenticationId.HighPart << 32) | TokenStats.AuthenticationId.LowPart);
     10843        else
     10844            kwErrPrintf("GetTokenInformation/TokenStatistics failed: %u\n", GetLastError());
     10845        CloseHandle(hToken);
     10846    }
     10847    else
     10848        kwErrPrintf("OpenProcessToken failed: %u\n", GetLastError());
     10849    return cchRet;
     10850}
     10851
     10852
     10853/**
     10854 * Look for and expand the special environment variable.
     10855 * 
     10856 * We the special variable contains elements like "@@VAR_NAME@@" that kmk
     10857 * couldn't accuratly determine.  Currently the following variables are
     10858 * implemented:
     10859 *     - "@@PROCESSOR_GROUP@@"   - The processor group number.
     10860 *     - "@@AUTHENTICATION_ID@@" - The authentication ID from the process token.
     10861 *     - "@@PID@@"               - The kWorker process ID.
     10862 *     - "@@@@"                  - Escaped "@@".
     10863 *     - "@@DEBUG_COUNTER@@"     - An ever increasing counter (starts at zero).
     10864 */ 
     10865static int kSubmitHandleSpecialEnvVar(KU32 cEnvVars, const char **papszEnvVars, const char *pszSpecialEnv, char **ppszToFree)
     10866{
     10867    KSIZE const cchSpecialEnv = kHlpStrLen(pszSpecialEnv);
     10868    KU32 i = cEnvVars;
     10869    while (i-- > 0)
     10870        if (   kHlpStrNComp(papszEnvVars[i], pszSpecialEnv, cchSpecialEnv) == 0
     10871            && papszEnvVars[i][cchSpecialEnv] == '=')
     10872        {
     10873            /* We will expand stuff like @@NAME@@ */
     10874            const char *pszValue = papszEnvVars[i];
     10875            KSIZE       offDst   = 0;
     10876            char        szTmp[1024];
     10877            for (;;)
     10878            {
     10879                const char *pszAt = kHlpStrChr(pszValue, '@');
     10880                while (pszAt && pszAt[1] != '@')
     10881                    pszAt = kHlpStrChr(pszAt + 1, '@');
     10882                if (pszAt)
     10883                {
     10884                    KSIZE cchSrc = pszAt - pszValue;
     10885                    if (offDst + cchSrc < sizeof(szTmp))
     10886                    {
     10887                        char szSrc[64];
     10888
     10889                        kHlpMemCopy(&szTmp[offDst], pszValue, cchSrc);
     10890                        offDst += cchSrc;
     10891                        pszValue = pszAt + 2;
     10892
     10893                        if (kHlpStrNComp(pszValue, "PROCESS_GROUP@@", 15) == 0)
     10894                        {
     10895                            pszValue += 15;
     10896                            if (g_iProcessGroup == -1)
     10897                                g_iProcessGroup = kwGetCurrentProcessorGroup();
     10898                            cchSrc = sprintf(szSrc, "%u", g_iProcessGroup);
     10899                        }
     10900                        else if (kHlpStrNComp(pszValue, "AUTHENTICATION_ID@@", 19) == 0)
     10901                        {
     10902                            pszValue += 19;
     10903                            cchSrc = kwGetCurrentAuthenticationIdAsString(szSrc);
     10904                        }
     10905                        else if (kHlpStrNComp(pszValue, "PID@@", 5) == 0)
     10906                        {
     10907                            pszValue += 5;
     10908                            cchSrc = sprintf(szSrc, "%d", getpid());
     10909                        }
     10910                        else if (kHlpStrNComp(pszValue, "@@", 2) == 0)
     10911                        {
     10912                            pszValue += 2;
     10913                            szSrc[0] = '@';
     10914                            szSrc[1] = '@';
     10915                            szSrc[2] = '\0';
     10916                            cchSrc = 2;
     10917                        }
     10918                        else if (kHlpStrNComp(pszValue, "DEBUG_COUNTER@@", 15) == 0)
     10919                        {
     10920                            static unsigned int s_iCounter = 0;
     10921                            pszValue += 15;
     10922                            cchSrc = sprintf(szSrc, "%u", s_iCounter++);
     10923                        }
     10924                        else
     10925                            return kwErrPrintfRc(42 + 6, "Special environment variable contains unknown reference: '%s'!\n",
     10926                                                 pszValue - 2);
     10927                        if (offDst + cchSrc < sizeof(szTmp))
     10928                        {
     10929                            kHlpMemCopy(&szTmp[offDst], szSrc, cchSrc);
     10930                            offDst += cchSrc;
     10931                            continue;
     10932                        }
     10933                    }
     10934                }
     10935                else
     10936                {
     10937                    KSIZE cchSrc = kHlpStrLen(pszValue);
     10938                    if (offDst + cchSrc < sizeof(szTmp))
     10939                    {
     10940                        kHlpMemCopy(&szTmp[offDst], pszValue, cchSrc);
     10941                        offDst += cchSrc;
     10942                        break;
     10943                    }
     10944                }
     10945                return kwErrPrintfRc(42 + 6, "Special environment variable value too long!\n");
     10946            }
     10947            szTmp[offDst] = '\0';
     10948
     10949            /* Return a copy of it: */
     10950            papszEnvVars[i] = *ppszToFree = kHlpDup(szTmp, offDst + 1);
     10951            if (papszEnvVars[i])
     10952            {
     10953                SetEnvironmentVariableA(pszSpecialEnv, kHlpStrChr(papszEnvVars[i], '=') + 1); /* hack */
     10954                return 0;
     10955            }
     10956            return kwErrPrintfRc(42 + 6, "Special environment variable: out of memory\n");
     10957        }
     10958
     10959    return kwErrPrintfRc(42 + 6, "Special environment variable not found: '%s'\n", pszSpecialEnv);
    1032610960}
    1032710961
     
    1033810972 * @param   cEnvVars            The number of environment variables.
    1033910973 * @param   papszEnvVars        The environment vector.
     10974 * @param   pszSpecialEnv       Name of special environment variable that
     10975 *                              requires selective expansion here.
    1034010976 * @param   fNoPchCaching       Whether to disable precompiled header file
    1034110977 *                              caching.  Avoid trouble when creating them.
     
    1034510981static int kSubmitHandleJobUnpacked(const char *pszExecutable, const char *pszCwd,
    1034610982                                    KU32 cArgs, const char **papszArgs, KBOOL fWatcomBrainDamange,
    10347                                     KU32 cEnvVars, const char **papszEnvVars, KBOOL fNoPchCaching,
    10348                                     KU32 cPostCmdArgs, const char **papszPostCmdArgs)
     10983                                    KU32 cEnvVars, const char **papszEnvVars, const char *pszSpecialEnv,
     10984                                    KBOOL fNoPchCaching, KU32 cPostCmdArgs, const char **papszPostCmdArgs)
    1034910985{
    1035010986    int rcExit;
    1035110987    PKWTOOL pTool;
     10988    char *pszSpecialEnvFree = NULL;
    1035210989
    1035310990    KW_LOG(("\n\nkSubmitHandleJobUnpacked: '%s' in '%s' cArgs=%u cEnvVars=%u cPostCmdArgs=%u\n",
     
    1036311000#endif
    1036411001    g_cJobs++;
     11002
     11003    /*
     11004     * Expand pszSpecialEnv if present.
     11005     */
     11006    if (*pszSpecialEnv)
     11007    {
     11008        rcExit = kSubmitHandleSpecialEnvVar(cEnvVars, papszEnvVars, pszSpecialEnv, &pszSpecialEnvFree);
     11009        if (!rcExit)
     11010        { /* likely */ }
     11011        else
     11012            return rcExit;
     11013    }
    1036511014
    1036611015    /*
     
    1043411083    else
    1043511084        rcExit = 42 + 1;
     11085    if (pszSpecialEnvFree)
     11086    {
     11087        SetEnvironmentVariableA(pszSpecialEnv, NULL); /* hack */
     11088        kHlpFree(pszSpecialEnvFree);
     11089    }
    1043611090    return rcExit;
    1043711091}
     
    1054411198                                    cbMsg -= 2;
    1054511199
    10546                                     /* Post command argument count (can be zero). */
    10547                                     if (cbMsg >= sizeof(KU32))
     11200                                    /* Name of special enviornment variable requiring selective expansion. */
     11201                                    if (cbMsg >= 1)
    1054811202                                    {
    10549                                         KU32 cPostCmdArgs;
    10550                                         kHlpMemCopy(&cPostCmdArgs, pszMsg, sizeof(cPostCmdArgs));
    10551                                         pszMsg += sizeof(cPostCmdArgs);
    10552                                         cbMsg  -= sizeof(cPostCmdArgs);
    10553 
    10554                                         if (cPostCmdArgs >= 0 && cPostCmdArgs < 32)
     11203                                        const char *pszSpecialEnv = pszMsg;
     11204                                        cbTmp = kHlpStrLen(pszMsg);
     11205                                        pszMsg += cbTmp + 1;
     11206                                        cbMsg  -= K_MIN(cbMsg, cbTmp + 1);
     11207
     11208                                        /* Post command argument count (can be zero). */
     11209                                        if (cbMsg >= sizeof(KU32))
    1055511210                                        {
    10556                                             char const *apszPostCmdArgs[32+1];
    10557                                             for (i = 0; i < cPostCmdArgs; i++)
     11211                                            KU32 cPostCmdArgs;
     11212                                            kHlpMemCopy(&cPostCmdArgs, pszMsg, sizeof(cPostCmdArgs));
     11213                                            pszMsg += sizeof(cPostCmdArgs);
     11214                                            cbMsg  -= sizeof(cPostCmdArgs);
     11215
     11216                                            if (cPostCmdArgs >= 0 && cPostCmdArgs < 32)
    1055811217                                            {
    10559                                                 apszPostCmdArgs[i] = pszMsg;
    10560                                                 cbTmp = kHlpStrLen(pszMsg) + 1;
    10561                                                 pszMsg += cbTmp;
    10562                                                 if (   cbTmp < cbMsg
    10563                                                     || (cbTmp == cbMsg && i + 1 == cPostCmdArgs))
    10564                                                     cbMsg -= cbTmp;
     11218                                                char const *apszPostCmdArgs[32+1];
     11219                                                for (i = 0; i < cPostCmdArgs; i++)
     11220                                                {
     11221                                                    apszPostCmdArgs[i] = pszMsg;
     11222                                                    cbTmp = kHlpStrLen(pszMsg) + 1;
     11223                                                    pszMsg += cbTmp;
     11224                                                    if (   cbTmp < cbMsg
     11225                                                        || (cbTmp == cbMsg && i + 1 == cPostCmdArgs))
     11226                                                        cbMsg -= cbTmp;
     11227                                                    else
     11228                                                    {
     11229                                                        cbMsg = KSIZE_MAX;
     11230                                                        break;
     11231                                                    }
     11232                                                }
     11233                                                if (cbMsg == 0)
     11234                                                {
     11235                                                    apszPostCmdArgs[cPostCmdArgs] = NULL;
     11236
     11237                                                    /*
     11238                                                     * The next step.
     11239                                                     */
     11240                                                    rcExit = kSubmitHandleJobUnpacked(pszExecutable, pszCwd,
     11241                                                                                      cArgs, papszArgs, fWatcomBrainDamange,
     11242                                                                                      cEnvVars, papszEnvVars, pszSpecialEnv,
     11243                                                                                      fNoPchCaching,
     11244                                                                                      cPostCmdArgs, apszPostCmdArgs);
     11245                                                }
     11246                                                else if (cbMsg == KSIZE_MAX)
     11247                                                    kwErrPrintf("Detected bogus message unpacking post command and its arguments!\n");
    1056511248                                                else
    10566                                                 {
    10567                                                     cbMsg = KSIZE_MAX;
    10568                                                     break;
    10569                                                 }
     11249                                                    kwErrPrintf("Message has %u bytes unknown trailing bytes\n", cbMsg);
    1057011250                                            }
    10571                                             if (cbMsg == 0)
    10572                                             {
    10573                                                 apszPostCmdArgs[cPostCmdArgs] = NULL;
    10574 
    10575                                                 /*
    10576                                                  * The next step.
    10577                                                  */
    10578                                                 rcExit = kSubmitHandleJobUnpacked(pszExecutable, pszCwd,
    10579                                                                                   cArgs, papszArgs, fWatcomBrainDamange,
    10580                                                                                   cEnvVars, papszEnvVars, fNoPchCaching,
    10581                                                                                   cPostCmdArgs, apszPostCmdArgs);
    10582                                             }
    10583                                             else if (cbMsg == KSIZE_MAX)
    10584                                                 kwErrPrintf("Detected bogus message unpacking post command and its arguments!\n");
    1058511251                                            else
    10586                                                 kwErrPrintf("Message has %u bytes unknown trailing bytes\n", cbMsg);
     11252                                                kwErrPrintf("Bogus post command argument count: %u %#x\n", cPostCmdArgs, cPostCmdArgs);
    1058711253                                        }
    1058811254                                        else
    10589                                             kwErrPrintf("Bogus post command argument count: %u %#x\n", cPostCmdArgs, cPostCmdArgs);
     11255                                            kwErrPrintf("Detected bogus message looking for the post command argument count!\n");
    1059011256                                    }
    1059111257                                    else
    10592                                         kwErrPrintf("Detected bogus message looking for the post command argument count!\n");
     11258                                        kwErrPrintf("Detected bogus message unpacking special environment variable!\n");
    1059311259                                }
    1059411260                                else
    10595                                     kwErrPrintf("Detected bogus message unpacking environment variables!\n");
     11261                                    kwErrPrintf("Detected bogus message unpacking flags!\n");
    1059611262                                kHlpFree((void *)papszEnvVars);
    1059711263                            }
     
    1088911555    const char *pszCwd = getcwd(szCwd, sizeof(szCwd));
    1089011556    KU32        cEnvVars;
     11557    char      **papszEnvVars;
     11558    const char *pszSpecialEnv = "";
     11559    const char *pszSpecialEnvFull = NULL;
    1089111560    KBOOL       fWatcomBrainDamange = K_FALSE;
    1089211561    KBOOL       fNoPchCaching = K_FALSE;
     
    1093411603        }
    1093511604
     11605        /* Optional directory change. */
     11606        if (   i < argc
     11607            && (   strcmp(argv[i], "--set-special") == 0
     11608                || strcmp(argv[i], "-s")      == 0 ) )
     11609        {
     11610            i++;
     11611            if (i >= argc)
     11612                return kwErrPrintfRc(2, "--set-special takes an argument!\n");
     11613            pszSpecialEnvFull = argv[i++];
     11614            putenv(pszSpecialEnvFull);
     11615            pszSpecialEnv = strdup(pszSpecialEnvFull);
     11616            *strchr(pszSpecialEnv, '=') = '\0';
     11617        }
     11618
    1093611619        /* Trigger breakpoint */
    1093711620        if (   i < argc
     
    1095811641
    1095911642    /*
    10960      * Do the job.
     11643     * Duplicate the environment.
    1096111644     */
    1096211645    cEnvVars = 0;
    1096311646    while (environ[cEnvVars] != NULL)
    1096411647        cEnvVars++;
    10965 
     11648    papszEnvVars = (char **)kHlpAllocZ(sizeof(papszEnvVars[0]) * (cEnvVars + 2));
     11649
     11650    /*
     11651     * Do the job.
     11652     */
    1096611653    for (j = 0; j < cRepeats; j++)
    1096711654    {
     11655        memcpy(papszEnvVars, environ, sizeof(papszEnvVars[0]) * cEnvVars);
    1096811656        rcExit = kSubmitHandleJobUnpacked(argv[i], pszCwd,
    1096911657                                          argc - i, &argv[i], fWatcomBrainDamange,
    10970                                           cEnvVars, environ, fNoPchCaching,
     11658                                          cEnvVars, papszEnvVars, pszSpecialEnv, fNoPchCaching,
    1097111659                                          0, NULL);
    1097211660        KW_LOG(("rcExit=%d\n", rcExit));
    1097311661        kwSandboxCleanupLate(&g_Sandbox);
     11662    }
     11663
     11664    if (getenv("KWORKER_STATS") != NULL)
     11665        kwPrintStats();
     11666
     11667# ifdef WITH_LOG_FILE
     11668    if (g_hLogFile != INVALID_HANDLE_VALUE && g_hLogFile != NULL)
     11669        CloseHandle(g_hLogFile);
     11670# endif
     11671    return rcExit;
     11672}
     11673
     11674
     11675/**
     11676 * Reads @a pszFile into memory and chops it up into an argument vector.
     11677 *
     11678 * @returns Pointer to the argument vector on success, NULL on failure.
     11679 * @param   pszFile         The file to load.
     11680 * @param   pcArgs          Where to return the number of arguments.
     11681 * @param   ppszFileContent Where to return the allocation.
     11682 */
     11683static char **kwFullTestLoadArgvFile(const char *pszFile, int *pcArgs, char **ppszFileContent)
     11684{
     11685    char **papszArgs = NULL;
     11686    FILE  *pFile     = fopen(pszFile, "r");
     11687    if (pFile)
     11688    {
     11689        long cbFile;
     11690        if (   fseek(pFile, 0, SEEK_END) == 0
     11691            && (cbFile = ftell(pFile)) >= 0
     11692            && fseek(pFile, 0, SEEK_SET) == 0)
     11693        {
     11694            char *pszFile = kHlpAllocZ(cbFile + 3);
     11695            if (pszFile)
     11696            {
     11697                size_t cbRead = fread(pszFile, 1, cbFile + 1, pFile);
     11698                if (   feof(pFile)
     11699                    && !ferror(pFile))
     11700                {
     11701                    size_t off        = 0;
     11702                    int    cArgs      = 0;
     11703                    int    cAllocated = 0;
     11704                    char   ch;
     11705
     11706                    pszFile[cbRead]     = '\0';
     11707                    pszFile[cbRead + 1] = '\0';
     11708                    pszFile[cbRead + 2] = '\0';
     11709
     11710                    while ((ch = pszFile[off]) != '\0')
     11711                    {
     11712                        char *pszArg;
     11713                        switch (ch)
     11714                        {
     11715                            case ' ':
     11716                            case '\t':
     11717                            case '\n':
     11718                            case '\r':
     11719                                off++;
     11720                                continue;
     11721
     11722                            case '\\':
     11723                                if (pszFile[off + 1] == '\n' || pszFile[off + 1] == '\r')
     11724                                {
     11725                                    off += 2;
     11726                                    continue;
     11727                                }
     11728                                /* fall thru */
     11729                            default:
     11730                                pszArg = &pszFile[off];
     11731                                do
     11732                                    ch = pszFile[++off];
     11733                                while (ch != '\0' && ch != ' ' && ch != '\t' && ch != '\n' && ch != '\r');
     11734                                pszFile[off++] = '\0';
     11735                                break;
     11736
     11737                            case '\'':
     11738                                pszArg = &pszFile[++off];
     11739                                while ((ch = pszFile[off]) != '\0' && ch != '\'')
     11740                                    off++;
     11741                                pszFile[off++] = '\0';
     11742                                break;
     11743
     11744                            case '\"': /** @todo escape sequences */
     11745                                pszArg = &pszFile[++off];
     11746                                while ((ch = pszFile[off]) != '\0' && ch != '"')
     11747                                    off++;
     11748                                pszFile[off++] = '\0';
     11749                                break;
     11750                        }
     11751                        if (cArgs + 1 >= cAllocated)
     11752                        {
     11753                            void *pvNew;
     11754                            cAllocated = cAllocated ? cAllocated * 2 : 16;
     11755                            pvNew = kHlpRealloc(papszArgs, cAllocated * sizeof(papszArgs[0]));
     11756                            if (pvNew)
     11757                                papszArgs = (char **)pvNew;
     11758                            else
     11759                            {
     11760                                kHlpFree(papszArgs);
     11761                                papszArgs = NULL;
     11762                                break;
     11763                            }
     11764                        }
     11765                        papszArgs[cArgs] = pszArg;
     11766                        papszArgs[++cArgs] = NULL;
     11767                    }
     11768                    *pcArgs = cArgs;
     11769                }
     11770                else
     11771                    kwErrPrintf("Error reading '%s'!\n", pszFile);
     11772            }
     11773            else
     11774                kwErrPrintf("Error allocating %lu bytes!\n", cbFile + 2);
     11775        }
     11776        else
     11777            kwErrPrintf("Error seeking '%s'!\n", pszFile);
     11778        fclose(pFile);
     11779    }
     11780    else
     11781        kwErrPrintf("Error opening '%s'!\n", pszFile);
     11782    return papszArgs;
     11783}
     11784
     11785/**
     11786 * Appends a string to an string vector (arguments or enviornment).
     11787 *
     11788 * @returns 0 on success, non-zero on failure (exit code).
     11789 * @param   ppapszVector    Pointer to the string pointer array.
     11790 * @param   pcEntries       Pointer to the array size.
     11791 * @param   pszAppend       The string to append.
     11792 */
     11793static int kwFullTestVectorAppend(const char ***ppapszVector, int *pcEntries, char const *pszAppend)
     11794{
     11795    unsigned cEntries = *pcEntries;
     11796    if (!(cEntries & 15))
     11797    {
     11798        void *pvNew = kHlpRealloc((void *)*ppapszVector, sizeof(char *) * (cEntries + 16 + 1));
     11799        if (pvNew)
     11800            *ppapszVector = (const char **)pvNew;
     11801        else
     11802            return kwErrPrintfRc(2, "Out of memory!\n");
     11803    }
     11804    (*ppapszVector)[cEntries] = pszAppend;
     11805    (*ppapszVector)[++cEntries] = NULL;
     11806    *pcEntries = cEntries;
     11807    return 0;
     11808}
     11809
     11810
     11811/**
     11812 * Parses arguments for --full-test.
     11813 *
     11814 * @returns 0 on success, non-zero on failure (exit code).
     11815 */
     11816static int kwFullTestRunParseArgs(PKWONETEST *ppHead, int *piState, int argc, char **argv,
     11817                                  const char *pszDefaultCwd, int cRecursions, const char *pszJobSrc)
     11818{
     11819    PKWONETEST pCur = *ppHead;
     11820    int i;
     11821    for (i = 0; i < argc; i++)
     11822    {
     11823        int         rc     = 0;
     11824        const char *pszArg = argv[i];
     11825        if (*pszArg == 'k' && kHlpStrComp(pszArg, "kSubmit") == 0)
     11826        {
     11827            if (*piState != 0)
     11828            {
     11829                pCur = (PKWONETEST)kHlpAllocZ(sizeof(*pCur));
     11830                if (!pCur)
     11831                    return kwErrPrintfRc(2, "Out of memory!\n");
     11832                pCur->fVirgin   = K_TRUE;
     11833                pCur->pszCwd    = pszDefaultCwd;
     11834                pCur->cRuns     = 1;
     11835                pCur->pNext     = *ppHead;
     11836                *ppHead = pCur;
     11837                *piState = 0;
     11838            }
     11839            else if (!pCur->fVirgin)
     11840                return kwErrPrintfRc(2, "Unexpected 'kSubmit' as argument #%u\n", i);
     11841            pCur->pszJobSrc = pszJobSrc;
     11842            pCur->iJobSrc   = i;
     11843            continue; /* (to stay virgin) */
     11844        }
     11845        else if (*pszArg == '-' && *piState == 0)
     11846        {
     11847            const char *pszValue = NULL;
     11848            char        ch       = *++pszArg;
     11849            pszArg++;
     11850            if (ch == '-')
     11851            {
     11852                ch = '\0';
     11853                if (*pszArg == '\0') /* -- */
     11854                    *piState = 2;
     11855                /* Translate or handle long options: */
     11856                else if (kHlpStrComp(pszArg, "putenv") == 0 || kHlpStrComp(pszArg, "set") == 0)
     11857                    ch = 'E';
     11858                else if (kHlpStrComp(pszArg, "special-env") == 0)
     11859                    ch = 's';
     11860                else if (kHlpStrComp(pszArg, "default-env") == 0)
     11861                {
     11862                    unsigned i;
     11863                    pCur->cEnvVars = 0;
     11864                    for (i = 0; environ[i] && rc == 0; i++)
     11865                        rc = kwFullTestVectorAppend(&pCur->papszEnvVars, &pCur->cEnvVars, kHlpStrDup(environ[i])); /* leaks; unchecked */
     11866                }
     11867                else if (kHlpStrComp(pszArg, "chdir") == 0)
     11868                    ch = 'C';
     11869                else if (kHlpStrComp(pszArg, "post-cmd") == 0)
     11870                    ch = 'P';
     11871                else if (kHlpStrComp(pszArg, "response-file") == 0)
     11872                    ch = '@';
     11873                else if (kHlpStrComp(pszArg, "runs") == 0)
     11874                    ch = 'R';
     11875                else if (kHlpStrComp(pszArg, "watcom-brain-damage") == 0)
     11876                    pCur->fWatcomBrainDamange = K_TRUE;
     11877                else if (kHlpStrComp(pszArg, "no-pch-caching") == 0)
     11878                    pCur->fNoPchCaching = K_TRUE;
     11879                else if (kHlpStrComp(pszArg, "executable") == 0)
     11880                    ch = 'e';
     11881                else if (kHlpStrComp(pszArg, "breakpoint") == 0)
     11882                {
     11883                    __debugbreak();
     11884                    continue; /* (to stay virgin) */
     11885                }
     11886                else
     11887                    return kwErrPrintfRc(2, "Unknown option: --%s\n", pszArg);
     11888                pszArg = "";
     11889            }
     11890
     11891            while (ch != '\0' && rc == 0)
     11892            {
     11893                /* Fetch value if needed: */
     11894                switch (ch)
     11895                {
     11896                    case '@':
     11897                    case 'e':
     11898                    case 'E':
     11899                    case 's':
     11900                    case 'C':
     11901                    case 'R':
     11902                        if (*pszArg == ':' || *pszArg == '=')
     11903                            pszValue = &pszArg[1];
     11904                        else if (*pszArg)
     11905                            pszValue = pszArg;
     11906                        else if (i + 1 < argc)
     11907                            pszValue = argv[++i];
     11908                        else
     11909                            return kwErrPrintfRc(2, "Option -%c takes a value\n", ch);
     11910                        pszArg = "";
     11911                        break;
     11912                }
     11913
     11914                /* Handle the option: */
     11915                switch (ch)
     11916                {
     11917                    case 'E':
     11918                        rc = kwFullTestVectorAppend(&pCur->papszEnvVars, &pCur->cEnvVars, pszValue);
     11919                        break;
     11920                    case 'C':
     11921                        pCur->pszCwd = pszValue;
     11922                        break;
     11923                    case 's':
     11924                        pCur->pszSpecialEnv = pszValue;
     11925                        break;
     11926                    case 'e':
     11927                        pCur->pszExecutable = pszValue;
     11928                        break;
     11929                    case 'P':
     11930                        *piState = 1;
     11931                        if (*pszArg)
     11932                            return kwErrPrintfRc(2, "Option -P cannot be followed by other options!\n");
     11933                        break;
     11934                    case 'R':
     11935                        pCur->cRuns = atoi(pszValue);
     11936                        if ((int)pCur->cRuns < 0)
     11937                            return kwErrPrintfRc(2, "Option -R takes a positive (or zero) integer as value: %s\n", pszValue);
     11938                        break;
     11939                    case '@':
     11940                        if (cRecursions < 5)
     11941                        {
     11942                            char    *pszLeaked = NULL;
     11943                            int      cArgs     = 0;
     11944                            char   **papszArgsLeaked = kwFullTestLoadArgvFile(pszValue, &cArgs, &pszLeaked);
     11945                            if (papszArgsLeaked)
     11946                            {
     11947                                rc = kwFullTestRunParseArgs(ppHead, piState, cArgs, papszArgsLeaked, pszDefaultCwd,
     11948                                                            cRecursions + 1, pszValue);
     11949                                pCur = *ppHead;
     11950                            }
     11951                            else
     11952                                return 2;
     11953                        }
     11954                        else
     11955                            return kwErrPrintfRc(2, "Too deep response file nesting!\n");
     11956                        break;
     11957                }
     11958
     11959                /* next */
     11960                ch = *pszArg++;
     11961            }
     11962        }
     11963        else if (*piState == 2)
     11964            rc = kwFullTestVectorAppend(&pCur->papszArgs, &pCur->cArgs, pszArg);
     11965        else if (*piState == 1)
     11966        {
     11967            if (pszArg[0] != '-' || pszArg[1] != '-' || pszArg[2] != '\0')
     11968                rc = kwFullTestVectorAppend(&pCur->papszPostCmdArgs, &pCur->cPostCmdArgs, pszArg);
     11969            else
     11970                *piState = 2;
     11971        }
     11972        else
     11973            return kwErrPrintfRc(2, "Unexpected argument: %s\n", pszArg);
     11974        if (rc)
     11975            return rc;
     11976        pCur->fVirgin = K_FALSE;
     11977    }
     11978    return 0;
     11979}
     11980
     11981
     11982/**
     11983 * Handles what comes after --full-test.
     11984 *
     11985 * @returns Exit code.
     11986 * @param   argc                Number of arguments after --full-test.
     11987 * @param   argv                Arguments after --full-test.
     11988 */
     11989static int kwFullTestRun(int argc, char **argv)
     11990{
     11991    char        szDefaultCwd[MAX_PATH];
     11992    const char *pszDefaultCwd = getcwd(szDefaultCwd, sizeof(szDefaultCwd));
     11993    KWONETEST   FirstTest;
     11994    PKWONETEST  pHead = &FirstTest;
     11995    PKWONETEST  pCur;
     11996    int         iState = 0;
     11997    int         rcExit;
     11998
     11999    /*
     12000     * Parse arguments.
     12001     */
     12002    kHlpMemSet(&FirstTest, 0, sizeof(FirstTest));
     12003    FirstTest.pszJobSrc = "command-line";
     12004    FirstTest.iJobSrc   = 1;
     12005    FirstTest.fVirgin   = K_TRUE;
     12006    FirstTest.pszCwd    = pszDefaultCwd;
     12007    FirstTest.cRuns     = 1;
     12008
     12009    rcExit = kwFullTestRunParseArgs(&pHead, &iState, argc, argv, pszDefaultCwd, 0, "command-line");
     12010    if (rcExit)
     12011        return rcExit;
     12012
     12013    /*
     12014     * Do the job.  LIFO ordering (see kSubmit).
     12015     */
     12016    for (pCur = pHead; pCur; pCur = pCur->pNext)
     12017    {
     12018        if (!pCur->pszExecutable && pCur->papszArgs)
     12019            pCur->pszExecutable = pCur->papszArgs[0];
     12020        if (   pCur->pszExecutable
     12021            && pCur->cArgs > 0
     12022            && pCur->cEnvVars > 0)
     12023        {
     12024            size_t const    cbEnvVarCopy     = sizeof(pCur->papszEnvVars[0]) * (pCur->cEnvVars + 1);
     12025            char ** const   papszEnvVarsCopy = (char **)kHlpDup(pCur->papszEnvVars, cbEnvVarCopy);
     12026            unsigned        iRun;
     12027
     12028            for (iRun = 0; iRun < pCur->cRuns; iRun++)
     12029            {
     12030                rcExit = kSubmitHandleJobUnpacked(pCur->pszExecutable, pCur->pszCwd,
     12031                                                  pCur->cArgs, pCur->papszArgs, pCur->fWatcomBrainDamange,
     12032                                                  pCur->cEnvVars, pCur->papszEnvVars, pCur->pszSpecialEnv,
     12033                                                  pCur->fNoPchCaching, pCur->cPostCmdArgs, pCur->papszPostCmdArgs);
     12034
     12035                KW_LOG(("rcExit=%d\n", rcExit));
     12036                kwSandboxCleanupLate(&g_Sandbox);
     12037
     12038                memcpy((void *)pCur->papszEnvVars, papszEnvVarsCopy, cbEnvVarCopy);
     12039            }
     12040            kHlpFree(papszEnvVarsCopy);
     12041        }
     12042        else
     12043            rcExit = kwErrPrintfRc(2, "Job is underspecified! %s%s%s (Job started with argument #%u, %s)\n",
     12044                                   pCur->pszExecutable ? "" : " No executable!",
     12045                                   pCur->cArgs < 1 ? " No arguments!" : "",
     12046                                   pCur->cEnvVars < 1 ? " No environment!" : "",
     12047                                   pCur->iJobSrc, pCur->pszJobSrc);
    1097412048    }
    1097512049
     
    1116712241        else if (strcmp(argv[i], "--test") == 0)
    1116812242            return kwTestRun(argc - i - 1, &argv[i + 1]);
     12243        else if (strcmp(argv[i], "--full-test") == 0)
     12244            return kwFullTestRun(argc - i - 1, &argv[i + 1]);
    1116912245        else if (strcmp(argv[i], "--priority") == 0)
    1117012246        {
  • trunk/src/kmk/kmkbuiltin/kSubmit.c

    r3224 r3313  
    121121    int                     fdSocket;
    122122#endif
     123
     124    /** Current history index (must mod with aHistory element count). */
     125    unsigned                iHistory;
     126    /** History.   */
     127    struct
     128    {
     129        /** Pointer to the message, NULL if none. */
     130        void               *pvMsg;
     131        /** The message size, zero if not present. */
     132        size_t              cbMsg;
     133    } aHistory[4];
    123134
    124135    /** What it's busy with.  NULL if idle. */
     
    181192
    182193#ifdef KBUILD_OS_WINDOWS
     194/** The processor group allocator state. */
     195static MKWINCHILDCPUGROUPALLOCSTATE g_SubmitProcessorGroupAllocator;
     196# if K_ARCH_BITS == 64
     197/** The processor group allocator state for 32-bit processes. */
     198static MKWINCHILDCPUGROUPALLOCSTATE g_SubmitProcessorGroupAllocator32;
     199# endif
     200#endif
     201
     202#ifdef KBUILD_OS_WINDOWS
    183203/** Pointer to kernel32!SetThreadGroupAffinity. */
    184204static BOOL (WINAPI *g_pfnSetThreadGroupAffinity)(HANDLE, const GROUP_AFFINITY*, GROUP_AFFINITY *);
     
    428448    {
    429449#ifdef KBUILD_OS_WINDOWS
    430         static DWORD        s_fDenyRemoteClients = ~(DWORD)0;
    431         wchar_t             wszPipeName[128];
    432         HANDLE              hWorkerPipe;
    433         int                 iProcessorGroup = -1; /** @todo determine process group. */
     450        static DWORD    s_fDenyRemoteClients = ~(DWORD)0;
     451        wchar_t         wszPipeName[128];
     452        HANDLE          hWorkerPipe;
     453        int             iProcessorGroup;
     454
     455# if K_ARCH_BITS == 64
     456        /** @todo make it return -1 if not applicable (e.g only one group).  */
     457        if (pWorker->cBits != 32)
     458            iProcessorGroup = MkWinChildAllocateCpuGroup(&g_SubmitProcessorGroupAllocator);
     459        else
     460            iProcessorGroup = MkWinChildAllocateCpuGroup(&g_SubmitProcessorGroupAllocator32);
     461# else
     462        iProcessorGroup = MkWinChildAllocateCpuGroup(&g_SubmitProcessorGroupAllocator);
     463# endif
    434464
    435465        /*
     
    464494                {
    465495                    extern int          process_priority; /* main.c */
    466                     wchar_t             wszCommandLine[MAX_PATH * 3];
     496                    wchar_t             wszCommandLine[MAX_PATH * 3 + 32];
    467497                    wchar_t            *pwszDst = wszCommandLine;
    468498                    size_t              cwcDst = K_ELEMENTS(wszCommandLine);
     
    490520                        cwcDst  -= cwc;
    491521                    }
     522                    if (iProcessorGroup >= 0)
     523                    {
     524                        cwc = _snwprintf(pwszDst, cwcDst, L" --group %d", iProcessorGroup);
     525                        assert(cwc > 0 && cwc < cwcDst);
     526                        pwszDst += cwc;
     527                        cwcDst  -= cwc;
     528                    }
    492529                    *pwszDst = '\0';
    493530
     
    549586                                warnx(pCtx, "warning: failed to set kWorker thread priority: %u\n", GetLastError());
    550587
    551                             if (iProcessorGroup >= 0)
     588                            if (iProcessorGroup >= 0 && g_pfnSetThreadGroupAffinity)
    552589                            {
    553590                                GROUP_AFFINITY NewAff = { ~(uintptr_t)0, (WORD)iProcessorGroup, 0, 0, 0 };
     
    789826 * @param   fWatcomBrainDamage  The wcc/wcc386 workaround.
    790827 * @param   fNoPchCaching       Whether to disable precompiled header caching.
     828 * @param   pszSpecialEnv       Environment variable (name=value) subject to
     829 *                              special expansion in kWorker.  NULL if none.
    791830 * @param   papszPostCmdArgs    The post command and it's arguments.
    792831 * @param   cPostCmdArgs        Number of post command argument, including the
     
    795834 */
    796835static void *kSubmitComposeJobMessage(const char *pszExecutable, char **papszArgs, char **papszEnvVars,
    797                                       const char *pszCwd, int fWatcomBrainDamage, int fNoPchCaching,
     836                                      const char *pszCwd, int fWatcomBrainDamage, int fNoPchCaching, const char *pszSpecialEnv,
    798837                                      char **papszPostCmdArgs, uint32_t cPostCmdArgs, uint32_t *pcbMsg)
    799838{
    800839    size_t   cbTmp;
     840    size_t   cbSpecialEnv;
    801841    uint32_t i;
    802842    uint32_t cbMsg;
     
    833873    cbMsg += 1; /* fNoPchCaching */
    834874
     875    cbSpecialEnv = pszSpecialEnv ? strchr(pszSpecialEnv, '=') - pszSpecialEnv : 0;
     876    cbMsg += cbSpecialEnv + 1;
     877
    835878    cbMsg += sizeof(cPostCmdArgs);
    836879    for (i = 0; i < cPostCmdArgs; i++)
     
    858901    pbCursor += cbTmp;
    859902
    860     /* argument */
     903    /* arguments */
    861904    memcpy(pbCursor, &cArgs, sizeof(cArgs));
    862905    pbCursor += sizeof(cArgs);
     
    884927    *pbCursor++ = fWatcomBrainDamage != 0;
    885928    *pbCursor++ = fNoPchCaching != 0;
     929
     930    /* Special environment variable name. */
     931    memcpy(pbCursor, pszSpecialEnv, cbSpecialEnv);
     932    pbCursor += cbSpecialEnv;
     933    *pbCursor++ = '\0';
    886934
    887935    /* post command */
     
    11081156#endif /* KBUILD_OS_WINDOWS */
    11091157
     1158
     1159/**
     1160 * Adds the given message to the history.
     1161 *
     1162 * @returns Pointer to old message, or NULL if no old msg to free.
     1163 * @param   pWorker             The worker instance.
     1164 * @param   pvMsg               The message.
     1165 * @param   cbMsg               The message size.
     1166 */
     1167static void *kSubmitUpdateHistory(PWORKERINSTANCE pWorker, void *pvMsg, size_t cbMsg)
     1168{
     1169    unsigned iHistory = pWorker->iHistory % K_ELEMENTS(pWorker->aHistory);
     1170    void    *pvRet;
     1171    pWorker->iHistory++;
     1172    pvRet = pWorker->aHistory[iHistory].pvMsg;
     1173    pWorker->aHistory[iHistory].pvMsg = pvMsg;
     1174    pWorker->aHistory[iHistory].cbMsg = cbMsg;
     1175    return pvRet;
     1176}
     1177
     1178typedef struct HISTORYDUMPBUF
     1179{
     1180    char           *pszBuf;
     1181    size_t          cbBuf;
     1182    size_t          off;
     1183    PKMKBUILTINCTX  pCtx;
     1184} HISTORYDUMPBUF;
     1185
     1186
     1187static void kSubmitDumpHistoryWrite(HISTORYDUMPBUF *pBuf, const char *pch, size_t cch)
     1188{
     1189    if (pBuf->off + cch >= pBuf->cbBuf)
     1190    {
     1191        size_t cbNew = pBuf->cbBuf ? pBuf->cbBuf * 2 : 65536;
     1192        while (pBuf->off + cch >= cbNew)
     1193            cbNew *= 2;
     1194        pBuf->pszBuf = (char *)xrealloc(pBuf->pszBuf, cbNew);
     1195        pBuf->cbBuf = cbNew;
     1196    }
     1197
     1198    memcpy(&pBuf->pszBuf[pBuf->off], pch, cch);
     1199    pBuf->off += cch;
     1200    pBuf->pszBuf[pBuf->off] = '\0';
     1201}
     1202
     1203static void kSubmitDumpHistoryPrintf(HISTORYDUMPBUF *pBuf, const char *pszFormat, ...)
     1204{
     1205    char szTmp[32];
     1206    va_list va;
     1207    va_start(va, pszFormat);
     1208    for (;;)
     1209    {
     1210        const char *pszPct = strchr(pszFormat, '%');
     1211        if (!pszPct)
     1212        {
     1213            kSubmitDumpHistoryWrite(pBuf, pszFormat, strlen(pszFormat));
     1214            return;
     1215        }
     1216        if (pszPct != pszFormat)
     1217        {
     1218            kSubmitDumpHistoryWrite(pBuf, pszFormat, pszPct - pszFormat);
     1219            pszFormat = pszPct;
     1220        }
     1221        pszFormat++;
     1222        switch (*pszFormat++)
     1223        {
     1224            case 's':
     1225            {
     1226                const char * const psz = va_arg(va, const char *);
     1227                size_t const       cch = strlen(psz);
     1228                if (memchr(psz, '\'', cch))
     1229                {
     1230                    kSubmitDumpHistoryWrite(pBuf, TUPLE("\"")); /** @todo what if there are '"' in the string? */
     1231                    kSubmitDumpHistoryWrite(pBuf, psz, cch);
     1232                    kSubmitDumpHistoryWrite(pBuf, TUPLE("\""));
     1233                }
     1234                else if (   !memchr(psz, ' ', cch)
     1235                         && !memchr(psz, '\t', cch)
     1236                         && !memchr(psz, '\n', cch)
     1237                         && !memchr(psz, '\r', cch)
     1238                         && !memchr(psz, '&', cch)
     1239                         && !memchr(psz, ';', cch)
     1240                         && !memchr(psz, '|', cch))
     1241                    kSubmitDumpHistoryWrite(pBuf, psz, cch);
     1242                else
     1243                {
     1244                    kSubmitDumpHistoryWrite(pBuf, TUPLE("'"));
     1245                    kSubmitDumpHistoryWrite(pBuf, psz, strlen(psz));
     1246                    kSubmitDumpHistoryWrite(pBuf, TUPLE("'"));
     1247                }
     1248                break;
     1249            }
     1250
     1251            case 'd':
     1252            {
     1253                int iValue = va_arg(va, int);
     1254                kSubmitDumpHistoryWrite(pBuf, szTmp, snprintf(szTmp, sizeof(szTmp), "%d", iValue));
     1255                break;
     1256            }
     1257
     1258            case 'u':
     1259            {
     1260                unsigned uValue = va_arg(va, unsigned);
     1261                kSubmitDumpHistoryWrite(pBuf, szTmp, snprintf(szTmp, sizeof(szTmp), "%u", uValue));
     1262                break;
     1263            }
     1264
     1265            case '%':
     1266                kSubmitDumpHistoryWrite(pBuf, "%s", 1);
     1267                break;
     1268
     1269            default:
     1270                assert(0);
     1271        }
     1272    }
     1273    va_end(va);
     1274}
     1275
     1276static void kSubmitDumpHistoryFlush(HISTORYDUMPBUF *pBuf)
     1277{
     1278    if (pBuf->off > 0)
     1279        output_write_text(pBuf->pCtx->pOut, 1, pBuf->pszBuf, pBuf->off);
     1280    pBuf->off = 0;
     1281}
     1282
     1283/**
     1284 * Dumps the history for this worker to stderr in the given context.
     1285 *
     1286 * @param   pCtx                The command execution context. (Typically not a
     1287 *                              real context.)
     1288 * @param   pWorker             The worker instance.
     1289 */
     1290static void kSubmitDumpHistory(PKMKBUILTINCTX pCtx, PWORKERINSTANCE pWorker)
     1291{
     1292    HISTORYDUMPBUF  Buf      = { NULL, 0, 0, pCtx };
     1293    int             iHistory = pWorker->iHistory;
     1294    unsigned        cDumped  = 0;
     1295
     1296    while (cDumped < K_ELEMENTS(pWorker->aHistory) && iHistory > 0)
     1297    {
     1298        unsigned const  idx    = (unsigned)--iHistory % K_ELEMENTS(pWorker->aHistory);
     1299        const char     *pszMsg = (const char *)pWorker->aHistory[idx].pvMsg;
     1300        ssize_t         cbMsg  = pWorker->aHistory[idx].cbMsg;
     1301        const char     *pszExe;
     1302        const char     *pszCwd;
     1303        uint32_t        i;
     1304        uint32_t        cArgs;
     1305        const char     *pszArgs;
     1306        size_t          cbArgs;
     1307        uint32_t        cEnvVars;
     1308        const char     *pszEnvVars;
     1309        size_t          cbEnvVars;
     1310        const char     *pszSpecialEnv;
     1311        char            fNoPchCaching;
     1312        char            fWatcomBrainDamage;
     1313        uint32_t        cPostArgs;
     1314        const char     *pszPostArgs;
     1315        size_t          cbPostArgs;
     1316
     1317        cDumped++;
     1318        if (!pszMsg || !cbMsg)
     1319            break;
     1320
     1321#define SKIP_BYTES(a_cbSkip)    do { pszMsg += (a_cbSkip); cbMsg -= (a_cbSkip); } while (0)
     1322#define SKIP_STR()              do { size_t const cbToSkip = strlen(pszMsg) + 1; SKIP_BYTES(cbToSkip); } while (0)
     1323#define SKIP_STRING_ARRAY(a_cStrings, a_cbPreable) do { \
     1324        for (i = 0; i < (a_cStrings) && cbMsg > 0; i++) { \
     1325            size_t const cbToSkip = (a_cbPreable) + strlen(pszMsg + (a_cbPreable)) + 1; \
     1326            SKIP_BYTES(cbToSkip); \
     1327        } } while (0)
     1328
     1329        /* Decode it: */
     1330        SKIP_BYTES(sizeof(uint32_t) + sizeof("JOB"));
     1331        pszExe = pszMsg;
     1332        SKIP_STR();
     1333        pszCwd = pszMsg;
     1334        SKIP_STR();
     1335
     1336        cArgs  = *(uint32_t *)pszMsg;
     1337        SKIP_BYTES(sizeof(uint32_t));
     1338        pszArgs = pszMsg;
     1339        SKIP_STRING_ARRAY(cArgs, 1 /*fbFlags*/);
     1340        cbArgs = pszMsg - pszArgs;
     1341
     1342        cEnvVars = *(uint32_t *)pszMsg;
     1343        SKIP_BYTES(sizeof(uint32_t));
     1344        pszEnvVars = pszMsg;
     1345        SKIP_STRING_ARRAY(cEnvVars, 0);
     1346        cbEnvVars = pszMsg - pszEnvVars;
     1347
     1348        fWatcomBrainDamage = pszMsg[0] != '\0';
     1349        fNoPchCaching = pszMsg[1] != '\0';
     1350        SKIP_BYTES(2);
     1351
     1352        pszSpecialEnv = pszMsg;
     1353        SKIP_STR();
     1354
     1355        cPostArgs = *(uint32_t *)pszMsg;
     1356        SKIP_BYTES(sizeof(uint32_t));
     1357        pszPostArgs = pszMsg;
     1358        SKIP_STRING_ARRAY(cPostArgs, 0);
     1359        cbPostArgs = pszMsg - pszPostArgs;
     1360
     1361        /* Produce parseable output: */
     1362        kSubmitDumpHistoryPrintf(&Buf, "kWorker %u/%u:\n\tkSubmit", (long)pWorker->pid, iHistory, pszExe);
     1363        if (fNoPchCaching)
     1364            kSubmitDumpHistoryWrite(&Buf, TUPLE(" --no-pch-caching"));
     1365        if (fWatcomBrainDamage)
     1366            kSubmitDumpHistoryWrite(&Buf, TUPLE(" --watcom-brain-damage"));
     1367        if (pszSpecialEnv)
     1368            kSubmitDumpHistoryPrintf(&Buf, " --special-env %s", pszSpecialEnv);
     1369        kSubmitDumpHistoryPrintf(&Buf, " --chdir %s \\\n", pszCwd);
     1370
     1371        pszMsg = pszEnvVars;
     1372        cbMsg  = cbEnvVars;
     1373        for (i = 0; i < cEnvVars && cbMsg > 0; i++)
     1374        {
     1375            kSubmitDumpHistoryPrintf(&Buf, "\t--putenv %s \\\n", pszMsg);
     1376            SKIP_STR();
     1377        }
     1378
     1379        if (cPostArgs > 0)
     1380        {
     1381            kSubmitDumpHistoryWrite(&Buf, TUPLE("\t--post-cmd "));
     1382            pszMsg = pszPostArgs;
     1383            cbMsg  = cbPostArgs;
     1384            for (i = 0; i < cPostArgs && cbMsg > 0; i++)
     1385            {
     1386                kSubmitDumpHistoryPrintf(&Buf, " %s", pszMsg);
     1387                SKIP_STR();
     1388            }
     1389            kSubmitDumpHistoryWrite(&Buf, TUPLE(" \\\n"));
     1390        }
     1391        kSubmitDumpHistoryWrite(&Buf, TUPLE("\t-- \\\n"));
     1392
     1393        pszMsg = pszArgs;
     1394        cbMsg  = cbArgs;
     1395        for (i = 0; i < cArgs && cbMsg > 0; i++)
     1396        {
     1397            SKIP_BYTES(1);
     1398            kSubmitDumpHistoryPrintf(&Buf, i + 1 < cArgs ? "\t%s \\\n" : "\t%s\n", pszMsg);
     1399            SKIP_STR();
     1400        }
     1401
     1402#undef SKIP_BYTES
     1403#undef SKIP_STR
     1404#undef SKIP_STRING_ARRAY
     1405    }
     1406
     1407    kSubmitDumpHistoryFlush(&Buf);
     1408    free(Buf.pszBuf);
     1409}
     1410
     1411
    11101412/**
    11111413 * Marks the worker active.
     
    11681470        if (pWorker->Result.s.bWorkerExiting)
    11691471            kSubmitCloseConnectOnExitingWorker(pCtx, pWorker);
     1472        if (pWorker->Result.s.rcExit && 1)
     1473            kSubmitDumpHistory(pCtx, pWorker);
    11701474        *pPidSpawned = 0;
    11711475        return pWorker->Result.s.rcExit;
     
    12471551        case STATUS_ILLEGAL_INSTRUCTION:        *piSigNo = SIGILL; break;
    12481552    }
     1553    if (pWorker->Result.s.rcExit && 1)
     1554        kSubmitDumpHistory(pCtx, pWorker);
    12491555    if (pWorker->Result.s.bWorkerExiting)
    12501556        kSubmitCloseConnectOnExitingWorker(pCtx, pWorker);
     
    14101716                           "usage: %s [-Z|--zap-env] [-E|--set <var=val>] [-U|--unset <var=val>]\n"
    14111717                           "           [-A|--append <var=val>] [-D|--prepend <var=val>]\n"
    1412                            "           [-C|--chdir <dir>] [--wcc-brain-damage] [--no-pch-caching]\n"
    1413                            "           [-3|--32-bit] [-6|--64-bit] [-v]\n"
     1718                           "           [-s|--special-env <var=val>] [-C|--chdir <dir>]\n"
     1719                           "           [--wcc-brain-damage] [--no-pch-caching]\n"
     1720                           "           [-3|--32-bit] [-6|--64-bit] [-v] [--debug-dump-history]\n"
    14141721                           "           [-P|--post-cmd <cmd> [args]] -- <program> [args]\n"
    14151722                           "   or: %s --help\n"
     
    14201727                           "    Zaps the environment. Position dependent.\n"
    14211728                           "  -E, --set <var>=[value]\n"
    1422                            "    Sets an enviornment variable putenv fashion. Position dependent.\n"
     1729                           "    Sets an environment variable putenv fashion. Position dependent.\n"
    14231730                           "  -U, --unset <var>\n"
    14241731                           "    Removes an environment variable. Position dependent.\n"
     
    14271734                           "  -D,--prepend <var>=<value>\n"
    14281735                           "    Prepends the given value to the environment variable.\n"
     1736                           "  -s,--special-env <var>=<value>\n"
     1737                           "    Same as --set, but flags the variable for further expansion\n"
     1738                           "    within kWorker. Replacements:\n"
     1739                           "      @@PROCESSOR_GROUP@@   - The processor group number.\n"
     1740                           "      @@AUTHENTICATION_ID@@ - The authentication ID from the process token.\n"
     1741                           "      @@PID@@               - The kWorker process ID.\n"
     1742                           "      @@@@                  - Escaped \"@@\".\n"
     1743                           "      @@DEBUG_COUNTER@@     - An ever increasing counter (starts at zero).\n"
    14291744                           "  -C, --chdir <dir>\n"
    14301745                           "    Specifies the current directory for the program.  Relative paths\n"
     
    14411756                           "  -v,--verbose\n"
    14421757                           "    More verbose execution.\n"
     1758                           "  --debug-dump-history\n"
     1759                           "    Dump the history as of the submitted command.  Handy for debuging\n"
     1760                           "    trouble caused by a previous job.\n"
    14431761                           "  -P|--post-cmd <cmd> ...\n"
    14441762                           "    For running a built-in command on the output, specifying the command\n"
     
    14581776int kmk_builtin_kSubmit(int argc, char **argv, char **envp, PKMKBUILTINCTX pCtx, struct child *pChild, pid_t *pPidSpawned)
    14591777{
     1778#ifdef KBUILD_OS_WINDOWS
     1779    static int      s_fInitialized      = 0;
     1780#endif
    14601781    int             rcExit = 0;
    14611782    int             iArg;
     
    14641785    char          **papszEnvVars;
    14651786    const char     *pszExecutable       = NULL;
     1787    const char     *pszSpecialEnv       = NULL;
    14661788    int             iPostCmd            = argc;
    14671789    int             cPostCmdArgs        = 0;
     
    14691791    int             fWatcomBrainDamage  = 0;
    14701792    int             fNoPchCaching       = 0;
     1793    int             fDebugDumpHistory   = 0;
    14711794    int             cVerbosity          = 0;
    14721795    size_t const    cbCwdBuf            = GET_PATH_MAX;
    14731796    PATH_VAR(szCwd);
     1797
     1798#ifdef KBUILD_OS_WINDOWS
     1799    /*
     1800     * First time thru we must perform some initializations.
     1801     */
     1802    if (s_fInitialized)
     1803    { }
     1804    else
     1805    {
     1806        MkWinChildInitCpuGroupAllocator(&g_SubmitProcessorGroupAllocator);
     1807# if K_ARCH_BITS == 64
     1808        MkWinChildInitCpuGroupAllocator(&g_SubmitProcessorGroupAllocator32);
     1809# endif
     1810        *(FARPROC *)&g_pfnSetThreadGroupAffinity = GetProcAddress(GetModuleHandleW(L"KERNEL32.DLL"), "SetThreadGroupAffinity");
     1811        s_fInitialized = 1;
     1812    }
     1813#endif
    14741814
    14751815    /*
     
    15331873                }
    15341874
     1875                if (strcmp(pszArg, "debug-dump-history") == 0)
     1876                {
     1877                    fDebugDumpHistory = 1;
     1878                    continue;
     1879                }
     1880
     1881
    15351882                /* convert to short. */
    15361883                if (strcmp(pszArg, "help") == 0)
     
    15511898                else if (strcmp(pszArg, "chdir") == 0)
    15521899                    chOpt = 'C';
     1900                else if (strcmp(pszArg, "set-special") == 0)
     1901                    chOpt = 's';
    15531902                else if (strcmp(pszArg, "post-cmd") == 0)
    15541903                    chOpt = 'P';
     
    15811930                    case 'D':
    15821931                    case 'e':
     1932                    case 's':
    15831933                        if (*pszArg != '\0')
    15841934                            pszValue = pszArg + (*pszArg == ':' || *pszArg == '=');
     
    16281978                    case 'C':
    16291979                        rcExit = kBuiltinOptChDir(pCtx, szCwd, cbCwdBuf, pszValue);
     1980                        if (rcExit == 0)
     1981                            break;
     1982                        return rcExit;
     1983
     1984                    case 's':
     1985                        if (pszSpecialEnv)
     1986                            return errx(pCtx, 1, "The -s option can only be used once!");
     1987                        pszSpecialEnv = pszValue;
     1988                        rcExit = kBuiltinOptEnvSet(pCtx, &papszEnvVars, &cEnvVars, &cAllocatedEnvVars, cVerbosity, pszValue);
    16301989                        if (rcExit == 0)
    16311990                            break;
     
    16872046        uint32_t        cbMsg;
    16882047        void           *pvMsg   = kSubmitComposeJobMessage(pszExecutable, &argv[iArg], papszEnvVars, szCwd,
    1689                                                            fWatcomBrainDamage, fNoPchCaching,
     2048                                                           fWatcomBrainDamage, fNoPchCaching, pszSpecialEnv,
    16902049                                                           &argv[iPostCmd], cPostCmdArgs, &cbMsg);
    16912050        PWORKERINSTANCE pWorker = kSubmitSelectWorkSpawnNewIfNecessary(pCtx, cBitsWorker, cVerbosity);
     
    17032062            rcExit = kSubmitSendJobMessage(pCtx, pWorker, pvMsg, cbMsg, 0 /*fNoRespawning*/, cVerbosity);
    17042063            if (rcExit == 0)
     2064            {
     2065                pvMsg = kSubmitUpdateHistory(pWorker, pvMsg, cbMsg);
     2066                if (fDebugDumpHistory)
     2067                    kSubmitDumpHistory(pCtx, pWorker);
    17052068                rcExit = kSubmitMarkActive(pCtx, pWorker, cVerbosity, pChild, pPidSpawned);
     2069            }
    17062070
    17072071            if (!g_fAtExitRegistered)
     
    17232087}
    17242088
    1725 
    1726 
  • trunk/src/kmk/w32/winchildren.c

    r3224 r3313  
    334334/** Pointer to childcare workers. */
    335335static PWINCHILDCAREWORKER *g_papChildCareworkers = NULL;
    336 /** The group index for the worker allocator.
    337  * This is ever increasing and must be modded by g_cProcessorGroups. */
    338 static unsigned             g_idxProcessorGroupAllocator = 0;
    339 /** The processor in group index for the worker allocator. */
    340 static unsigned             g_idxProcessorInGroupAllocator = 0;
     336/** The processor group allocator state. */
     337static MKWINCHILDCPUGROUPALLOCSTATE g_ProcessorGroupAllocator;
    341338/** Number of processor groups in the system.   */
    342339static unsigned             g_cProcessorGroups = 1;
     
    468465                pacProcessorsInGroup[iGroup] = g_pfnGetActiveProcessorCount(iGroup);
    469466
    470             /* We shift the starting group with the make nesting level as part of
    471                our very simple distribution strategy. */
    472             g_idxProcessorGroupAllocator = makelevel;
     467            MkWinChildInitCpuGroupAllocator(&g_ProcessorGroupAllocator);
    473468        }
    474469        else
     
    26352630
    26362631/**
     2632 * Initializes the processor group allocator.
     2633 *
     2634 * @param   pState              The allocator to initialize.
     2635 */
     2636void MkWinChildInitCpuGroupAllocator(PMKWINCHILDCPUGROUPALLOCSTATE pState)
     2637{
     2638    /* We shift the starting group with the make nesting level as part of
     2639       our very simple distribution strategy. */
     2640    pState->idxGroup = makelevel;
     2641    pState->idxProcessorInGroup = 0;
     2642}
     2643
     2644/**
     2645 * Allocate CPU group for the next child process.
     2646 *
     2647 * @returns CPU group.
     2648 * @param   pState              The allocator state.  Must be initialized by
     2649 *                              MkWinChildInitCpuGroupAllocator().
     2650 */
     2651unsigned int MkWinChildAllocateCpuGroup(PMKWINCHILDCPUGROUPALLOCSTATE pState)
     2652{
     2653    unsigned int iGroup = 0;
     2654    if (g_cProcessorGroups > 1)
     2655    {
     2656        unsigned int cMaxInGroup;
     2657        unsigned int cInGroup;
     2658
     2659        iGroup = pState->idxGroup % g_cProcessorGroups;
     2660
     2661        /* Advance.  We employ a very simple strategy that does 50% in
     2662           each group for each group cycle.  Odd processor counts are
     2663           caught in odd group cycles.  The init function selects the
     2664           starting group based on make nesting level to avoid stressing
     2665           out the first group. */
     2666        cInGroup = ++pState->idxProcessorInGroup;
     2667        cMaxInGroup = g_pacProcessorsInGroup[iGroup];
     2668        if (   !(cMaxInGroup & 1)
     2669            || !((pState->idxGroup / g_cProcessorGroups) & 1))
     2670            cMaxInGroup /= 2;
     2671        else
     2672            cMaxInGroup = cMaxInGroup / 2 + 1;
     2673        if (cInGroup >= cMaxInGroup)
     2674        {
     2675            pState->idxProcessorInGroup = 0;
     2676            pState->idxGroup++;
     2677        }
     2678    }
     2679    return iGroup;
     2680}
     2681
     2682/**
    26372683 * Creates another childcare worker.
    26382684 *
     
    26542700            {
    26552701                /* Before we start the thread, assign it to a processor group. */
    2656                 if (g_cProcessorGroups > 1)
    2657                 {
    2658                     unsigned int cMaxInGroup;
    2659                     unsigned int cInGroup;
    2660                     unsigned int iGroup = g_idxProcessorGroupAllocator % g_cProcessorGroups;
    2661                     pWorker->iProcessorGroup = iGroup;
    2662 
    2663                     /* Advance.  We employ a very simple strategy that does 50% in
    2664                        each group for each group cycle.  Odd processor counts are
    2665                        caught in odd group cycles.  The init function selects the
    2666                        starting group based on make nesting level to avoid stressing
    2667                        out the first group. */
    2668                     cInGroup = ++g_idxProcessorInGroupAllocator;
    2669                     cMaxInGroup = g_pacProcessorsInGroup[iGroup];
    2670                     if (   !(cMaxInGroup & 1)
    2671                         || !((g_idxProcessorGroupAllocator / g_cProcessorGroups) & 1))
    2672                         cMaxInGroup /= 2;
    2673                     else
    2674                         cMaxInGroup = cMaxInGroup / 2 + 1;
    2675                     if (cInGroup >= cMaxInGroup)
    2676                     {
    2677                         g_idxProcessorInGroupAllocator = 0;
    2678                         g_idxProcessorGroupAllocator++;
    2679                     }
    2680                 }
     2702                pWorker->iProcessorGroup = MkWinChildAllocateCpuGroup(&g_ProcessorGroupAllocator);
    26812703
    26822704                /* Try start the thread. */
     
    34143436 * that completed children is the typical source of these tokens (esp. for kmk).
    34153437 *
    3416  * @returns Zero if completed children, event handle if waiting is required.
     3438 * @returns Zero if no active children, event handle if waiting is required.
    34173439 */
    34183440intptr_t MkWinChildGetCompleteEventHandle(void)
  • trunk/src/kmk/w32/winchildren.h

    r3200 r3313  
    2626#ifndef INCLUDED_WINCHILDREN_H
    2727#define INCLUDED_WINCHILDREN_H
     28
     29/** Child processor group allocator state. */
     30typedef struct MKWINCHILDCPUGROUPALLOCSTATE
     31{
     32    /** The group index for the worker allocator.
     33     * This is ever increasing and must be modded by g_cProcessorGroups. */
     34    unsigned int    idxGroup;
     35    /** The processor in group index for the worker allocator. */
     36    unsigned int    idxProcessorInGroup;
     37} MKWINCHILDCPUGROUPALLOCSTATE;
     38/** Pointer to a CPU group allocator state.   */
     39typedef MKWINCHILDCPUGROUPALLOCSTATE *PMKWINCHILDCPUGROUPALLOCSTATE;
    2840
    2941#ifdef DECLARE_HANDLE
     
    6880int     MkWinChildCreate(char **papszArgs, char **papszEnv, const char *pszShell, struct child *pMkChild, pid_t *pPid);
    6981int     MkWinChildCreateWithStdOutPipe(char **papszArgs, char **papszEnv, int fdErr, pid_t *pPid, int *pfdReadPipe);
     82void    MkWinChildInitCpuGroupAllocator(PMKWINCHILDCPUGROUPALLOCSTATE pState);
     83unsigned int MkWinChildAllocateCpuGroup(PMKWINCHILDCPUGROUPALLOCSTATE pState);
     84
    7085#ifdef KMK
    7186struct KMKBUILTINENTRY;
     
    86101                                   char **papszEnvVars, const char *pszCwd, BOOL pafReplace[3], HANDLE pahReplace[3]);
    87102# endif
    88 #endif
     103#endif /* KMK */
    89104int     MkWinChildKill(pid_t pid, int iSignal, struct child *pMkChild);
    90105int     MkWinChildWait(int fBlock, pid_t *pPid, int *piExitCode, int *piSignal, int *pfCoreDumped, struct child **ppMkChild);
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette