Ignore:
Timestamp:
Mar 27, 2018, 8:09:23 PM (7 years ago)
Author:
bird
Message:

kmk/win: Catch output from processes spawned by kmk_redirect. Made imagecase threadsafe and made winchildren use it.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/kmk/w32/imagecache.c

    r3140 r3195  
    2626/* No GNU coding style here! */
    2727
    28 /*******************************************************************************
    29 *   Header Files                                                               *
    30 *******************************************************************************/
     28/*********************************************************************************************************************************
     29*   Header Files                                                                                                                 *
     30*********************************************************************************************************************************/
    3131#include "makeint.h"
    3232
     
    3434
    3535
    36 /*******************************************************************************
    37 *   Structures and Typedefs                                                    *
    38 *******************************************************************************/
     36/*********************************************************************************************************************************
     37*   Structures and Typedefs                                                                                                      *
     38*********************************************************************************************************************************/
    3939typedef struct EXECCACHEENTRY
    4040{
     
    4242    unsigned                uHash;
    4343    /** The name length. */
    44     unsigned                cchName;
     44    unsigned                cwcName;
    4545    /** Pointer to the next name with the same hash. */
    4646    struct EXECCACHEENTRY  *pNext;
    4747    /** When it was last referenced. */
    4848    unsigned                uLastRef;
    49     /** The module handle. */
     49    /** The module handle, LOAD_LIBRARY_AS_DATAFILE. */
    5050    HMODULE                 hmod1;
    51     /** The module handle. */
     51    /** The module handle, DONT_RESOLVE_DLL_REFERENCES. */
    5252    HMODULE                 hmod2;
    5353    /** The executable path. */
    54     char                    szName[1];
     54    wchar_t                 wszName[1];
    5555} EXECCACHEENTRY;
    5656typedef EXECCACHEENTRY *PEXECCACHEENTRY;
    5757
    58 /*******************************************************************************
    59 *   Global Variables                                                           *
    60 *******************************************************************************/
     58
     59/*********************************************************************************************************************************
     60*   Global Variables                                                                                                             *
     61*********************************************************************************************************************************/
     62/** Critical section serializing all access. */
     63static CRITICAL_SECTION g_CritSect;
     64/** Set if initialized. */
     65static int volatile     g_fInitialized = 0;
    6166/** The number of cached images. */
    6267static unsigned         g_cCached;
     
    6974/** The hash table. */
    7075static PEXECCACHEENTRY  g_apHashTab[EXECCACHE_HASHTAB_SIZE];
     76
     77
     78/** A sleepy approach to do-once. */
     79static void kmk_cache_lazy_init(void)
     80{
     81    if (_InterlockedCompareExchange(&g_fInitialized, -1, 0) == 0)
     82    {
     83        InitializeCriticalSection(&g_CritSect);
     84        _InterlockedExchange(&g_fInitialized, 1);
     85    }
     86    else
     87        while (g_fInitialized != 1)
     88            Sleep(1);
     89}
    7190
    7291
     
    83102   elsewhere. */
    84103
    85 static unsigned execcache_calc_hash(const char *psz, unsigned *pcch)
    86 {
    87     unsigned char  *puch = (unsigned char *)psz;
    88     unsigned        hash = 0;
    89     int             ch;
    90 
    91     while ((ch = *puch++))
     104static unsigned execcache_calc_hash(const wchar_t *pwsz, size_t *pcch)
     105{
     106    wchar_t const  * const pwszStart = pwsz;
     107    unsigned               hash = 0;
     108    int                    ch;
     109
     110    while ((ch = *pwsz++) != L'\0')
    92111        hash = ch + (hash << 6) + (hash << 16) - hash;
    93112
    94     *pcch = (unsigned)(puch - psz - 1);
     113    *pcch = (size_t)(pwsz - pwszStart - 1);
    95114    return hash;
    96115}
    97116
    98 
    99 extern void kmk_cache_exec_image(const char *pszExec)
    100 {
    101     /*
    102      * Lookup the name.
    103      */
    104     unsigned            cchName;
    105     const unsigned      uHash = execcache_calc_hash(pszExec, &cchName);
     117/**
     118 * Caches two memory mappings of the specified image so that it isn't flushed
     119 * from the kernel's cache mananger.
     120 *
     121 * Not sure exactly how much this actually helps, but whatever...
     122 *
     123 * @param   pwszExec    The executable.
     124 */
     125extern void kmk_cache_exec_image_w(const wchar_t *pwszExec)
     126{
     127    /*
     128     * Prepare name lookup and to lazy init.
     129     */
     130    size_t              cwcName;
     131    const unsigned      uHash = execcache_calc_hash(pwszExec, &cwcName);
    106132    PEXECCACHEENTRY    *ppCur = &g_apHashTab[uHash % EXECCACHE_HASHTAB_SIZE];
    107     PEXECCACHEENTRY     pCur  = *ppCur;
     133    PEXECCACHEENTRY     pCur;
     134
     135    if (g_fInitialized != 1)
     136        kmk_cache_lazy_init();
     137
     138    /*
     139     * Do the lookup.
     140     */
     141    EnterCriticalSection(&g_CritSect);
     142    pCur = *ppCur;
    108143    while (pCur)
    109144    {
    110145        if (   pCur->uHash   == uHash
    111             && pCur->cchName == cchName
    112             && !memcmp(pCur->szName, pszExec, cchName))
     146            && pCur->cwcName == cwcName
     147            && !memcmp(pCur->wszName, pwszExec, cwcName * sizeof(wchar_t)))
    113148        {
    114149            pCur->uLastRef = ++g_uNow;
     150            LeaveCriticalSection(&g_CritSect);
    115151            return;
    116152        }
     
    118154        pCur = pCur->pNext;
    119155    }
     156    LeaveCriticalSection(&g_CritSect);
    120157
    121158    /*
    122159     * Not found, create a new entry.
    123160     */
    124     pCur = xmalloc(sizeof(*pCur) + cchName);
     161    pCur = xmalloc(sizeof(*pCur) + cwcName * sizeof(wchar_t));
    125162    pCur->uHash    = uHash;
    126     pCur->cchName  = cchName;
     163    pCur->cwcName  = (unsigned)cwcName;
    127164    pCur->pNext    = NULL;
    128165    pCur->uLastRef = ++g_uNow;
    129     memcpy(pCur->szName, pszExec, cchName + 1);
    130     pCur->hmod1 = LoadLibraryEx(pszExec, NULL, LOAD_LIBRARY_AS_DATAFILE);
     166    memcpy(pCur->wszName, pwszExec, (cwcName + 1) * sizeof(wchar_t));
     167    pCur->hmod1 = LoadLibraryExW(pwszExec, NULL, LOAD_LIBRARY_AS_DATAFILE);
    131168    if (pCur->hmod1 != NULL)
    132         pCur->hmod2 = LoadLibraryEx(pszExec, NULL, DONT_RESOLVE_DLL_REFERENCES);
     169        pCur->hmod2 = LoadLibraryExW(pwszExec, NULL, DONT_RESOLVE_DLL_REFERENCES);
    133170    else
    134171        pCur->hmod2 = NULL;
    135172
    136     *ppCur = pCur;
    137     g_cCached++;
    138 }
    139 
     173    /*
     174     * Insert it.
     175     * Take into account that we might've been racing other threads,
     176     * fortunately we don't evict anything from the cache.
     177     */
     178    EnterCriticalSection(&g_CritSect);
     179    if (*ppCur != NULL)
     180    {
     181        /* Find new end of chain and check for duplicate. */
     182        PEXECCACHEENTRY pCur2 = *ppCur;
     183        while (pCur2)
     184        {
     185            if (   pCur->uHash   == uHash
     186                && pCur->cwcName == cwcName
     187                && !memcmp(pCur->wszName, pwszExec, cwcName * sizeof(wchar_t)))
     188                break;
     189            ppCur = &pCur->pNext;
     190            pCur = pCur->pNext;
     191        }
     192
     193    }
     194    if (*ppCur == NULL)
     195    {
     196        *ppCur = pCur;
     197        g_cCached++;
     198        LeaveCriticalSection(&g_CritSect);
     199    }
     200    else
     201    {
     202        LeaveCriticalSection(&g_CritSect);
     203
     204        if (pCur->hmod1 != NULL)
     205            FreeLibrary(pCur->hmod1);
     206        if (pCur->hmod2 != NULL)
     207            FreeLibrary(pCur->hmod2);
     208        free(pCur);
     209    }
     210}
     211
     212extern void kmk_cache_exec_image_a(const char *pszExec)
     213{
     214    wchar_t wszExec[260];
     215    int cwc = MultiByteToWideChar(CP_ACP, 0 /*fFlags*/, pszExec, strlen(pszExec) + 1, wszExec, 260);
     216    if (cwc > 0)
     217        kmk_cache_exec_image_w(wszExec);
     218}
     219
Note: See TracChangeset for help on using the changeset viewer.