Changeset 3159 for trunk/src/kmk/w32


Ignore:
Timestamp:
Mar 19, 2018, 2:37:13 PM (7 years ago)
Author:
bird
Message:

kmk/win: Some fixes & docs.

Location:
trunk/src/kmk/w32
Files:
2 edited

Legend:

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

    r3158 r3159  
    2525
    2626/* No GNU coding style here atm, convert if upstreamed. */
     27
     28/** @page pg_win_children   Windows child process creation and managment
     29 *
     30 * This new implementation aims at addressing the following:
     31 *
     32 *      1. Speed up process creation by doing the expensive CreateProcess call
     33 *         in a worker thread.
     34 *
     35 *      2. No 64 process limit imposed by WaitForMultipleObjects.
     36 *
     37 *      3. Better distribute jobs among processor groups.
     38 *
     39 *      4. Offloading more expensive kmkbuiltin operations to worker threads,
     40 *         making the main thread focus on managing child processes.
     41 *
     42 *      5. Output synchronization using reusable pipes [not yet implemented].
     43 *
     44 *
     45 * To be quite honest, the first item (CreateProcess expense) didn't occur to me
     46 * at first and was more of a sideeffect discovered along the way.  A test
     47 * rebuilding IPRT went from 4m52s to 3m19s on a 8 thread system.
     48 *
     49 * The 2nd and 3rd goals are related to newer build servers that have lots of
     50 * CPU threads and various Windows NT (aka NT OS/2 at the time) design choices
     51 * made in the late 1980ies.
     52 *
     53 * WaitForMultipleObjects does not support waiting for more than 64 objects,
     54 * unlike poll and select.  This is just something everyone ends up having to
     55 * work around in the end.
     56 *
     57 * Affinity masks are uintptr_t sized, so 64-bit hosts can only manage 64
     58 * processors and 32-bit only 32.  Workaround was introduced with Windows 7
     59 * (IIRC) and is called processor groups.  The CPU threads are grouped into 1 or
     60 * more groups of up to 64 processors.  Processes are generally scheduled to a
     61 * signle processor group at first, but threads may be changed to be scheduled
     62 * on different groups.  This code will try distribute children evenly among the
     63 * processor groups, using a very simple algorithm (see details in code).
     64 *
     65 */
     66
    2767
    2868/*********************************************************************************************************************************
     
    66106    /** Normal child process. */
    67107    WINCHILDTYPE_PROCESS,
     108#ifdef KMK
    68109    /** kmkbuiltin command. */
    69110    WINCHILDTYPE_BUILTIN,
     
    72113    /** kmk_redirect job. */
    73114    WINCHILDTYPE_REDIRECT,
     115#endif
    74116    /** End of valid child types. */
    75117    WINCHILDTYPE_END
     
    247289static unsigned volatile    g_idxLastChildcareWorker = 0;
    248290
     291/** Temporary RW lock for serializing kmkbuiltin_redirect and CreateProcess. */
     292static SRWLOCK              g_RWLock;
    249293
    250294
     
    320364        }
    321365    }
     366
     367    /* Temporary: */
     368    InitializeSRWLock(&g_RWLock);
    322369}
    323370
     
    12051252    if (rc == 0)
    12061253    {
     1254        AcquireSRWLockShared(&g_RWLock); /* temporary */
     1255
    12071256        /*
    12081257         * Populate startup info.
     
    12481297                              TRUE /*fInheritHandles*/, fFlags, pwszzEnvironment, NULL /*pwsz*/, &StartupInfo, &ProcInfo);
    12491298        rc = GetLastError();
     1299        ReleaseSRWLockShared(&g_RWLock); /* temporary */
    12501300        if (fRet)
    12511301        {
     
    13151365}
    13161366
     1367#ifdef KMK
     1368
    13171369/**
    13181370 * Childcare worker: handle builtin command.
     
    13661418    mkWinChildcareWorkerWaitForProcess(pWorker, pChild, pChild->u.Redirect.hProcess);
    13671419}
     1420
     1421#endif /* KMK */
    13681422
    13691423/**
     
    14351489                        mkWinChildcareWorkerThreadHandleProcess(pWorker, pChild);
    14361490                        break;
     1491#ifdef KMK
    14371492                    case WINCHILDTYPE_BUILTIN:
    14381493                        mkWinChildcareWorkerThreadHandleBuiltin(pWorker, pChild);
     
    14441499                        mkWinChildcareWorkerThreadHandleRedirect(pWorker, pChild);
    14451500                        break;
     1501#endif
     1502                    default:
     1503                        assert(0);
    14461504                }
    14471505
     
    16381696        }
    16391697
     1698#ifdef KMK
     1699
    16401700        case WINCHILDTYPE_BUILTIN:
    16411701            assert(0);
     
    16571717            }
    16581718            break;
     1719
     1720#endif /* KMK */
     1721
     1722        default:
     1723            assert(0);
    16591724    }
    16601725
     
    18901955}
    18911956
     1957#ifdef KMK
     1958
    18921959/**
    18931960 * Interface used by kSubmit.c for registering stuff to wait on.
     
    19191986    return mkWinChildPushToCareWorker(pChild, pPid);
    19201987}
     1988
     1989#endif /* CONFIG_NEW_WIN_CHILDREN */
    19211990
    19221991/**
     
    19432012                    pChild->iSignal = iSignal;
    19442013                    break;
     2014
     2015#ifdef KMK
    19452016
    19462017                case WINCHILDTYPE_SUBMIT:
     
    19582029                case WINCHILDTYPE_BUILTIN:
    19592030                    break;
     2031
     2032#endif /* KMK */
     2033
     2034                default:
     2035                    assert(0);
    19602036            }
    19612037        }
     
    20152091        case WINCHILDTYPE_PROCESS:
    20162092            break;
     2093#ifdef KMK
    20172094        case WINCHILDTYPE_BUILTIN:
    20182095            break;
     
    20212098        case WINCHILDTYPE_REDIRECT:
    20222099            break;
     2100#endif /* KMK */
    20232101        default:
    20242102            assert(0);
    20252103    }
    20262104    mkWinChildDelete(pChild);
     2105
     2106#ifdef KMK
     2107    /* Flush the volatile directory cache. */
     2108    dir_cache_invalid_after_job();
     2109#endif
    20272110    return 0;
    20282111}
    20292112
    2030 
     2113/**
     2114 * Get the child completed event handle.
     2115 *
     2116 * Needed when w32os.c is waiting for a job token to become available, given
     2117 * that completed children is the typical source of these tokens (esp. for kmk).
     2118 *
     2119 * @returns Event handle.
     2120 */
    20312121intptr_t MkWinChildGetCompleteEventHandle(void)
    20322122{
    20332123    return (intptr_t)g_hEvtWaitChildren;
    20342124}
    2035 
    20362125
    20372126/**
     
    20532142    int                     rc;
    20542143
    2055 /** @todo this code needs testing... */
    2056 
    20572144    /*
    20582145     * Get the executable name.
     
    20842171    GetStartupInfoW(&StartupInfo);
    20852172    if (!CreateProcessW(wszImageName, pwszCommandLine, NULL /*pProcSecAttr*/, NULL /*pThreadSecAttr*/,
    2086                         TRUE /*fInheritHandles*/, 0 /*fFlags*/, pwszzEnvironment, NULL /*pwsz*/,
     2173                        TRUE /*fInheritHandles*/, CREATE_UNICODE_ENVIRONMENT, pwszzEnvironment, NULL /*pwsz*/,
    20872174                        &StartupInfo, &ProcInfo))
    20882175        ON(fatal, NILF, _("MkWinChildReExecMake: CreateProcessW failed: %u\n"), GetLastError());
     
    21032190        if (dwStatus == WAIT_OBJECT_0)
    21042191        {
    2105             if (GetExitCodeProcess(ProcInfo.hProcess, &dwExitCode))
     2192            if (!GetExitCodeProcess(ProcInfo.hProcess, &dwExitCode))
     2193            {
    21062194                ON(fatal, NILF, _("MkWinChildReExecMake: GetExitCodeProcess failed: %u\n"), GetLastError());
    2107             else
    21082195                dwExitCode = -2222;
     2196            }
    21092197        }
    21102198        else if (dwStatus)
     
    21172205}
    21182206
    2119 
     2207/** Temporary serialization with kmkbuiltin_redirect. */
     2208void MkWinChildExclusiveAcquire(void)
     2209{
     2210    AcquireSRWLockExclusive(&g_RWLock);
     2211}
     2212
     2213/** Temporary serialization with kmkbuiltin_redirect. */
     2214void MkWinChildExclusiveRelease(void)
     2215{
     2216    ReleaseSRWLockExclusive(&g_RWLock);
     2217}
     2218
     2219/**
     2220 * Implementation of the CLOSE_ON_EXEC macro.
     2221 *
     2222 * @returns errno value.
     2223 * @param   fd          The file descriptor to hide from children.
     2224 */
    21202225int MkWinChildUnrelatedCloseOnExec(int fd)
    21212226{
     
    21282233                return 0;
    21292234        }
     2235        return errno;
    21302236    }
    21312237    return EINVAL;
    21322238}
    21332239
    2134 
    2135 
  • trunk/src/kmk/w32/winchildren.h

    r3156 r3159  
    3636int     MkWinChildKill(pid_t pid, int iSignal, struct child *pMkChild);
    3737int     MkWinChildWait(int fBlock, pid_t *pPid, int *piExitCode, int *piSignal, int *pfCoreDumped, struct child **ppMkChild);
     38void    MkWinChildExclusiveAcquire(void);
     39void    MkWinChildExclusiveRelease(void);
    3840
    3941#undef  CLOSE_ON_EXEC
Note: See TracChangeset for help on using the changeset viewer.