VirtualBox

Changeset 2843 in kBuild


Ignore:
Timestamp:
Aug 28, 2016 3:31:02 PM (9 years ago)
Author:
bird
Message:

kmk: kSubmit is mostly done.

Location:
trunk/src/kmk
Files:
2 added
1 deleted
8 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/kmk/Makefile.kmk

    r2816 r2843  
    129129        getloadavg.c \
    130130        w32/subproc/misc.c \
    131         w32/subproc/sub_proc.c \
    132131        w32/subproc/w32err.c \
    133132        w32/pathstuff.c \
     
    245244        kbuild-object.c
    246245
     246kmk_SOURCES.win = \
     247        w32/subproc/sub_proc.c
     248
    247249kmk_DEFS.freebsd.x86 = CONFIG_WITHOUT_THREADS
    248250
     
    276278        kmkbuiltin/rm.c \
    277279        kmkbuiltin/rmdir.c \
     280        kmkbuiltin/kSubmit.c \
    278281        kmkbuiltin/sleep.c \
    279282        kmkbuiltin/test.c \
     
    459462        vpath.c \
    460463        remote-stub.c
     464
     465kmk_gmake_SOURCES.win = \
     466        w32/subproc/sub_proc.c
    461467
    462468
     
    510516        remote-stub.c
    511517
     518kmk_fgmake_SOURCES.win = \
     519        w32/subproc/sub_proc.c
     520
    512521
    513522include $(FILE_KBUILD_SUB_FOOTER)
     
    545554$(kmk_0_OUTDIR)/grp.h: | $(call DIRDEP,$(kmk_0_OUTDIR))
    546555        $(ECHO_EXT) > $@
     556
     557
     558ifeq ($(KBUILD_TARGET),win)
     559 #
     560 # tstFileInfo
     561 #
     562 PROGRAMS.win += tstFileInfo
     563 tstFileInfo_TEMPLATE = BIN
     564 tstFileInfo_SOURCES = w32/tstFileInfo.c
     565endif
    547566
    548567
  • trunk/src/kmk/config.h.win

    r2766 r2843  
    443443
    444444/* Define to `int' if <sys/types.h> does not define. */
    445 #define pid_t int
     445/* Note (bird)! sub_proc.c needs this to be pointer sized. */
     446#define pid_t intptr_t
    446447
    447448/* Define to `int' if <sys/types.h> doesn't define. */
  • trunk/src/kmk/job.c

    r2754 r2843  
    13201320      child->pid = 0;
    13211321      if (p2 != argv)
    1322         rc = kmk_builtin_command (*p2, &argv_spawn, &child->pid);
     1322        rc = kmk_builtin_command (*p2, &argv_spawn, &child->pid, child);
    13231323      else
    13241324        {
     
    13261326          while (argv[argc])
    13271327            argc++;
    1328           rc = kmk_builtin_command_parsed (argc, argv, &argv_spawn, &child->pid);
     1328          rc = kmk_builtin_command_parsed (argc, argv, &argv_spawn, &child->pid, child);
    13291329        }
    13301330
  • trunk/src/kmk/kmkbuiltin.c

    r2591 r2843  
    4343#endif
    4444
    45 int kmk_builtin_command(const char *pszCmd, char ***ppapszArgvToSpawn, pid_t *pPidSpawned)
     45int kmk_builtin_command(const char *pszCmd, struct child *pChild, char ***ppapszArgvToSpawn, pid_t *pPidSpawned)
    4646{
    4747    int         argc;
     
    155155     */
    156156    if (!*pszCmd)
    157         rc = kmk_builtin_command_parsed(argc, argv, ppapszArgvToSpawn, pPidSpawned);
     157        rc = kmk_builtin_command_parsed(argc, argv, pChild, ppapszArgvToSpawn, pPidSpawned);
    158158    else
    159159        rc = 1;
     
    167167
    168168
    169 int kmk_builtin_command_parsed(int argc, char **argv, char ***ppapszArgvToSpawn, pid_t *pPidSpawned)
     169int kmk_builtin_command_parsed(int argc, char **argv, struct child *pChild, char ***ppapszArgvToSpawn, pid_t *pPidSpawned)
    170170{
    171171    const char *pszCmd = argv[0];
    172     int         iumask;
     172    int         iUmask;
    173173    int         rc;
    174174
     
    184184
    185185    /*
    186      * String switch on the command.
    187      */
    188     iumask = umask(0);
    189     umask(iumask);
     186     * String switch on the command (frequent stuff at the top).
     187     */
     188    iUmask = umask(0);
     189    umask(iUmask);
    190190    if (!strcmp(pszCmd, "append"))
    191191        rc = kmk_builtin_append(argc, argv, environ);
     
    198198    else if (!strcmp(pszCmd, "kDepIDB"))
    199199        rc = kmk_builtin_kDepIDB(argc, argv, environ);
     200#ifdef KBUILD_OS_WINDOWS
     201    else if (!strcmp(pszCmd, "kSubmit"))
     202        rc = kmk_builtin_kSubmit(argc, argv, environ, pChild, pPidSpawned);
     203#endif
    200204    else if (!strcmp(pszCmd, "mkdir"))
    201205        rc = kmk_builtin_mkdir(argc, argv, environ);
     
    239243     */
    240244    g_progname = "kmk";                 /* paranoia, make sure it's not pointing at a freed argv[0]. */
    241     umask(iumask);
     245    umask(iUmask);
    242246
    243247
     
    261265
    262266        *ppapszArgvToSpawn = NULL;
    263         rc = kmk_builtin_command_parsed(argc_new, argv_new, ppapszArgvToSpawn, pPidSpawned);
     267        rc = kmk_builtin_command_parsed(argc_new, argv_new, pChild, ppapszArgvToSpawn, pPidSpawned);
    264268
    265269        free(argv_new[0]);
  • trunk/src/kmk/kmkbuiltin.h

    r2736 r2843  
    55
    66/*
    7  * Copyright (c) 2005-2010 knut st. osmundsen <[email protected]>
     7 * Copyright (c) 2005-2016 knut st. osmundsen <[email protected]>
    88 *
    99 * This file is part of kBuild.
     
    2424 */
    2525
     26#ifndef ___kmk_kmkbuiltin_h___
     27#define ___kmk_kmkbuiltin_h___
     28
    2629#ifdef _MSC_VER
    2730# ifndef pid_t /* see config.h.win */
    28 #  define pid_t int
     31#  define pid_t intptr_t /* Note! sub_proc.c needs it to be pointer sized. */
    2932# endif
    3033#else
     
    3235#endif
    3336
    34 int kmk_builtin_command(const char *pszCmd, char ***ppapszArgvToSpawn, pid_t *pPidSpawned);
    35 int kmk_builtin_command_parsed(int argc, char **argv, char ***ppapszArgvToSpawn, pid_t *pPidSpawned);
     37int kmk_builtin_command(const char *pszCmd, struct child *pChild, char ***ppapszArgvToSpawn, pid_t *pPidSpawned);
     38int kmk_builtin_command_parsed(int argc, char **argv, struct child *pChild, char ***ppapszArgvToSpawn, pid_t *pPidSpawned);
    3639
    3740extern int kmk_builtin_append(int argc, char **argv, char **envp);
     
    5659#endif
    5760                            );
     61#ifdef KBUILD_OS_WINDOWS
     62extern int kmk_builtin_kSubmit(int argc, char **argv, char **envp, struct child *pChild, pid_t *pPidSpawned);
     63extern int kSubmitSubProcGetResult(intptr_t pvUser, int *prcExit, int *piSigNo);
     64extern int kSubmitSubProcKill(intptr_t pvUser, int iSignal);
     65#endif
    5866extern int kmk_builtin_kDepIDB(int argc, char **argv, char **envp);
    5967extern int kmk_builtin_kDepObj(int argc, char **argv, char **envp);
     
    6371extern int kbuild_version(const char *);
    6472
     73#endif
     74
  • trunk/src/kmk/kmkbuiltin/kSubmit.c

    r2842 r2843  
    5050# include <unistd.h>
    5151#endif
     52#ifdef KBUILD_OS_WINDOWS
     53# include "sub_proc.h"
     54#endif
    5255
    5356#include "kbuild.h"
     
    7982    /** The process ID of the kWorker process. */
    8083    pid_t                   pid;
     84    union
     85    {
     86        struct
     87        {
     88            /** The exit code. */
     89            int32_t         rcExit;
     90            /** Set to 1 if the worker is exiting. */
     91            uint8_t         bWorkerExiting;
     92            uint8_t         abUnused[3];
     93        } s;
     94        uint8_t             ab[8];
     95    } Result;
     96    /** Number of result bytes read alread.  */
     97    size_t                  cbResultRead;
     98
    8199#ifdef KBUILD_OS_WINDOWS
    82100    /** The process handle. */
     
    86104    /** For overlapped read (have valid event semaphore). */
    87105    OVERLAPPED              OverlappedRead;
    88     /** The 32-bit exit code read bufffer. */
    89     uint32_t                u32ReadResult;
    90106#else
    91107    /** The socket descriptor we use to talk to the kWorker process. */
     
    126142static unsigned             g_uWorkerSeqNo = 0;
    127143#endif
     144/** Set if we've registred the atexit handler already. */
     145static int                  g_fAtExitRegistered = 0;
    128146
    129147/** @var g_cArchBits
     
    150168
    151169
     170
    152171/**
    153172 * Unlinks a worker instance from a list.
     
    219238
    220239    pList->cEntries++;
     240}
     241
     242
     243/**
     244 * Remove worker from the process ID hash table.
     245 *
     246 * @param   pWorker             The worker.
     247 */
     248static void kSubmitPidHashRemove(PWORKERINSTANCE pWorker)
     249{
     250    size_t idxHash = KWORKER_PID_HASH(pWorker->pid);
     251    if (g_apPidHash[idxHash] == pWorker)
     252        g_apPidHash[idxHash] = pWorker->pNext;
     253    else
     254    {
     255        PWORKERINSTANCE pPrev = g_apPidHash[idxHash];
     256        while (pPrev && pPrev->pNext != pWorker)
     257            pPrev = pPrev->pNext;
     258        assert(pPrev != NULL);
     259        if (pPrev)
     260            pPrev->pNext = pWorker->pNext;
     261    }
     262    pWorker->pid = -1;
    221263}
    222264
     
    384426static int kSubmitRespawnWorker(PWORKERINSTANCE pWorker, int cVerbosity)
    385427{
    386     size_t idxHash;
    387 
    388428    /*
    389429     * Clean up after the old worker.
     
    394434    /* Close the pipe handle first, breaking the pipe in case it's not already
    395435       busted up.  Close the event semaphore too before waiting for the process. */
    396     if (!CloseHandle(pWorker->hPipe))
    397         warnx("CloseHandle(pWorker->hPipe): %u", GetLastError());
    398     pWorker->hPipe = INVALID_HANDLE_VALUE;
     436    if (pWorker->hPipe != INVALID_HANDLE_VALUE)
     437    {
     438        if (!CloseHandle(pWorker->hPipe))
     439            warnx("CloseHandle(pWorker->hPipe): %u", GetLastError());
     440        pWorker->hPipe = INVALID_HANDLE_VALUE;
     441    }
    399442
    400443    if (!CloseHandle(pWorker->OverlappedRead.hEvent))
     
    421464    int     rc;
    422465
    423     if (close(pWorker->fdSocket) != 0)
    424         warn("close(pWorker->fdSocket)");
    425     pWorker->fdSocket = -1;
     466    if (pWorker->fdSocket != -1)
     467    {
     468        if (close(pWorker->fdSocket) != 0)
     469            warn("close(pWorker->fdSocket)");
     470        pWorker->fdSocket = -1;
     471    }
    426472
    427473    kill(pWorker->pid, SIGTERM);
     
    434480     * Unlink it from the hash table.
    435481     */
    436     idxHash = KWORKER_PID_HASH(pWorker->pid);
    437     if (g_apPidHash[idxHash] == pWorker)
    438         g_apPidHash[idxHash] = pWorker->pNext;
    439     else
    440     {
    441         PWORKERINSTANCE pPrev = g_apPidHash[idxHash];
    442         while (pPrev && pPrev->pNext != pWorker)
    443             pPrev = pPrev->pNext;
    444         assert(pPrev != NULL);
    445         if (pPrev)
    446             pPrev->pNext = pWorker->pNext;
    447     }
    448     pWorker->pid = -1;
     482    kSubmitPidHashRemove(pWorker);
    449483
    450484    /*
     
    598632 * @param   pvMsg               The message to send.
    599633 * @param   cbMsg               The size of the message.
     634 * @param   fNoRespawning       Set if
    600635 * @param   cVerbosity          The verbosity level.
    601636 */
    602 static int kSubmitSendJobMessage(PWORKERINSTANCE pWorker, void const *pvMsg, uint32_t cbMsg, int cVerbosity)
    603 {
    604     int cRetries = 1;
    605     for (;; cRetries--)
     637static int kSubmitSendJobMessage(PWORKERINSTANCE pWorker, void const *pvMsg, uint32_t cbMsg, int fNoRespawning, int cVerbosity)
     638{
     639    int cRetries;
     640
     641    /*
     642     * Respawn the worker if it stopped by itself and we closed the pipe already.
     643     */
     644#ifdef KBUILD_OS_WINDOWS
     645    if (pWorker->hPipe == INVALID_HANDLE_VALUE)
     646#else
     647    if (pWorker->fdSocket == -1)
     648#endif
     649    {
     650        if (!fNoRespawning)
     651        {
     652            if (cVerbosity > 0)
     653                fprintf(stderr,  "kSubmit: Respawning worker (#1)...\n");
     654            if (kSubmitRespawnWorker(pWorker, cVerbosity) != 0)
     655                return 2;
     656        }
     657
     658    }
     659
     660    /*
     661     * Restart-on-broken-pipe loop. Necessary?
     662     */
     663    for (cRetries = !fNoRespawning ? 1 : 0; ; cRetries--)
    606664    {
    607665        /*
     
    650708         * Broken connection. Try respawn the worker.
    651709         */
     710        if (cVerbosity > 0)
     711            fprintf(stderr,  "kSubmit: Respawning worker (#2)...\n");
    652712        if (kSubmitRespawnWorker(pWorker, cVerbosity) != 0)
    653713            return 2;
    654714    }
    655715}
     716
     717
     718/**
     719 * Closes the connection on a worker that said it is going to exit now.
     720 *
     721 * This is a way of dealing with imperfect resource management in the worker, it
     722 * will monitor it a little and trigger a respawn when it looks bad.
     723 *
     724 * This function just closes the pipe / socket connection to the worker.  The
     725 * kSubmitSendJobMessage function will see this a trigger a respawn the next
     726 * time the worker is engaged.  This will usually mean there's a little delay in
     727 * which the process can terminate without us having to actively wait for it.
     728 *
     729 * @param   pWorker             The worker instance.
     730 */
     731static void kSubmitCloseConnectOnExitingWorker(PWORKERINSTANCE pWorker)
     732{
     733#ifdef KBUILD_OS_WINDOWS
     734    if (!CloseHandle(pWorker->hPipe))
     735        warnx("CloseHandle(pWorker->hPipe): %u", GetLastError());
     736    pWorker->hPipe = INVALID_HANDLE_VALUE;
     737#else
     738    if (close(pWorker->fdSocket) != 0)
     739        warn("close(pWorker->fdSocket)");
     740    pWorker->fdSocket = -1;
     741#endif
     742}
     743
     744
     745#ifdef KBUILD_OS_WINDOWS
     746
     747/**
     748 * Handles read failure.
     749 *
     750 * @returns Exit code.
     751 * @param   pWorker             The worker instance.
     752 * @param   dwErr               The error code.
     753 */
     754static int kSubmitWinReadFailed(PWORKERINSTANCE pWorker, DWORD dwErr)
     755{
     756    DWORD dwExitCode;
     757
     758    if (pWorker->cbResultRead == 0)
     759        errx(1, "ReadFile failed: %u", dwErr);
     760    else
     761        errx(1, "ReadFile failed: %u (read %u bytes)", dwErr, pWorker->cbResultRead);
     762    assert(dwErr != 0);
     763
     764    /* Complete the result. */
     765    pWorker->Result.s.rcExit         = 127;
     766    pWorker->Result.s.bWorkerExiting = 1;
     767    pWorker->cbResultRead            = sizeof(pWorker->Result);
     768
     769    if (GetExitCodeProcess(pWorker->hProcess, &dwExitCode))
     770    {
     771        if (dwExitCode != 0)
     772            pWorker->Result.s.rcExit = dwExitCode;
     773    }
     774
     775    return dwErr != 0 ? (int)(dwErr & 0x7fffffff) : 0x7fffffff;
     776
     777}
     778
     779
     780/**
     781 * Used by
     782 * @returns 0 if we got the whole result, -1 if I/O is pending, windows last
     783 *          error on ReadFile failure.
     784 * @param   pWorker             The worker instance.
     785 */
     786static int kSubmitReadMoreResultWin(PWORKERINSTANCE pWorker)
     787{
     788    /*
     789     * Set up the result read, telling the sub_proc.c unit about it.
     790     */
     791    while (pWorker->cbResultRead < sizeof(pWorker->Result))
     792    {
     793        DWORD cbRead = 0;
     794
     795        BOOL fRc = ResetEvent(pWorker->OverlappedRead.hEvent);
     796        assert(fRc); (void)fRc;
     797
     798        pWorker->OverlappedRead.Offset     = 0;
     799        pWorker->OverlappedRead.OffsetHigh = 0;
     800
     801        if (!ReadFile(pWorker->hPipe, &pWorker->Result.ab[pWorker->cbResultRead],
     802                     sizeof(pWorker->Result) - pWorker->cbResultRead,
     803                     &cbRead,
     804                     &pWorker->OverlappedRead))
     805        {
     806            DWORD dwErr = GetLastError();
     807            if (dwErr == ERROR_IO_PENDING)
     808                return 1;
     809            return kSubmitWinReadFailed(pWorker, GetLastError());
     810        }
     811
     812        pWorker->cbResultRead += cbRead;
     813        assert(pWorker->cbResultRead <= sizeof(pWorker->Result));
     814    }
     815    return 0;
     816}
     817
     818#endif /* KBUILD_OS_WINDOWS */
     819
     820/**
     821 * Marks the worker active.
     822 *
     823 * On windows this involves setting up the async result read and telling
     824 * sub_proc.c about the process.
     825 *
     826 * @returns Exit code.
     827 * @param   pWorker             The worker instance to mark as active.
     828 * @param   cVerbosity          The verbosity level.
     829 * @param   pChild              The kmk child to associate the job with.
     830 * @param   pPidSpawned         If @a *pPidSpawned is non-zero if the child is
     831 *                              running, otherwise the worker is already done
     832 *                              and we've returned the exit code of the job.
     833 */
     834static int kSubmitMarkActive(PWORKERINSTANCE pWorker, int cVerbosity, struct child *pChild, pid_t *pPidSpawned)
     835{
     836#ifdef KBUILD_OS_WINDOWS
     837    int rc;
     838#endif
     839
     840    pWorker->cbResultRead = 0;
     841
     842#ifdef KBUILD_OS_WINDOWS
     843    /*
     844     * Setup the async result read on windows.  If we're slow and the worker
     845     * very fast, this may actually get the result immediately.
     846     */
     847l_again:
     848    rc = kSubmitReadMoreResultWin(pWorker);
     849    if (rc == -1)
     850    {
     851        if (process_kmk_register_submit(pWorker->OverlappedRead.hEvent, (intptr_t)pWorker) == 0)
     852        { /* likely */ }
     853        else
     854        {
     855            /* We need to do the waiting here because sub_proc.c has too much to do. */
     856            warnx("Too many processes for sub_proc.c to handle!");
     857            WaitForSingleObject(pWorker->OverlappedRead.hEvent, INFINITE);
     858            goto l_again;
     859        }
     860    }
     861    else
     862    {
     863        assert(rc == 0 || pWorker->Result.s.rcExit != 0);
     864        if (pWorker->Result.s.bWorkerExiting)
     865            kSubmitCloseConnectOnExitingWorker(pWorker);
     866        *pPidSpawned = 0;
     867        return pWorker->Result.s.rcExit;
     868    }
     869#endif
     870
     871    /*
     872     * Mark it busy and move it to the active instance.
     873     */
     874    pWorker->pBusyWith = pChild;
     875    *pPidSpawned = pWorker->pid;
     876
     877    kSubmitListUnlink(&g_IdleList, pWorker);
     878    kSubmitListAppend(&g_BusyList, pWorker);
     879    return 0;
     880}
     881
     882
     883#ifdef KBUILD_OS_WINDOWS
     884
     885/**
     886 * Retrieve the worker child result.
     887 *
     888 * If incomplete, we restart the ReadFile operation like kSubmitMarkActive does.
     889 *
     890 * @returns 0 on success, -1 if ReadFile was restarted.
     891 * @param   pvUser              The worker instance.
     892 * @param   prcExit             Where to return the exit code.
     893 * @param   piSigNo             Where to return the signal number.
     894 */
     895int kSubmitSubProcGetResult(intptr_t pvUser, int *prcExit, int *piSigNo)
     896{
     897    PWORKERINSTANCE pWorker = (PWORKERINSTANCE)pvUser;
     898
     899    /*
     900     * Get the overlapped result.  There should be one since we're here
     901     * because of a satisfied WaitForMultipleObject.
     902     */
     903    DWORD cbRead = 0;
     904    if (GetOverlappedResult(pWorker->hPipe, &pWorker->OverlappedRead, &cbRead, TRUE))
     905    {
     906        pWorker->cbResultRead += cbRead;
     907        assert(pWorker->cbResultRead <= sizeof(pWorker->Result));
     908
     909        /* More to be read? */
     910        while (pWorker->cbResultRead < sizeof(pWorker->Result))
     911        {
     912            int rc = kSubmitReadMoreResultWin(pWorker);
     913            if (rc == -1)
     914                return -1;
     915            assert(rc == 0 || pWorker->Result.s.rcExit != 0);
     916        }
     917        assert(pWorker->cbResultRead == sizeof(pWorker->Result));
     918    }
     919    else
     920    {
     921        DWORD dwErr = GetLastError();
     922        kSubmitWinReadFailed(pWorker, dwErr);
     923    }
     924
     925    /*
     926     * Okay, we've got a result.
     927     */
     928    *prcExit = pWorker->Result.s.rcExit;
     929    switch (pWorker->Result.s.rcExit)
     930    {
     931        default:                                *piSigNo = 0; break;
     932        case CONTROL_C_EXIT:                    *piSigNo = SIGINT; break;
     933        case STATUS_INTEGER_DIVIDE_BY_ZERO:     *piSigNo = SIGFPE; break;
     934        case STATUS_ACCESS_VIOLATION:           *piSigNo = SIGSEGV; break;
     935        case STATUS_PRIVILEGED_INSTRUCTION:
     936        case STATUS_ILLEGAL_INSTRUCTION:        *piSigNo = SIGILL; break;
     937    }
     938    return 0;
     939}
     940
     941
     942int kSubmitSubProcKill(intptr_t pvUser, int iSignal)
     943{
     944    return -1;
     945}
     946
     947#endif /* KBUILD_OS_WINDOWS */
     948
     949
     950/**
     951 * atexit callback that trigger worker termination.
     952 */
     953static void kSubmitAtExitCallback(void)
     954{
     955    PWORKERINSTANCE pWorker;
     956    DWORD           msStartTick;
     957    DWORD           cKillRaids = 0;
     958
     959    /*
     960     * Tell all the workers to exit by breaking the connection.
     961     */
     962    for (pWorker = g_IdleList.pHead; pWorker != NULL; pWorker = pWorker->pNext)
     963        kSubmitCloseConnectOnExitingWorker(pWorker);
     964    for (pWorker = g_BusyList.pHead; pWorker != NULL; pWorker = pWorker->pNext)
     965        kSubmitCloseConnectOnExitingWorker(pWorker);
     966
     967    /*
     968     * Wait a little while for them to stop.
     969     */
     970    Sleep(0);
     971    msStartTick = GetTickCount();
     972    for (;;)
     973    {
     974        /*
     975         * Collect handles of running processes.
     976         */
     977        PWORKERINSTANCE apWorkers[MAXIMUM_WAIT_OBJECTS];
     978        HANDLE          ahHandles[MAXIMUM_WAIT_OBJECTS];
     979        DWORD           cHandles;
     980
     981        for (pWorker = g_IdleList.pHead; pWorker != NULL; pWorker = pWorker->pNext)
     982            if (pWorker->hProcess != INVALID_HANDLE_VALUE)
     983            {
     984                if (cHandles < MAXIMUM_WAIT_OBJECTS)
     985                {
     986                    apWorkers[cHandles] = pWorker;
     987                    ahHandles[cHandles] = pWorker->hProcess;
     988                }
     989                cHandles++;
     990            }
     991        for (pWorker = g_BusyList.pHead; pWorker != NULL; pWorker = pWorker->pNext)
     992            if (pWorker->hProcess != INVALID_HANDLE_VALUE)
     993            {
     994                if (cHandles < MAXIMUM_WAIT_OBJECTS)
     995                {
     996                    apWorkers[cHandles] = pWorker;
     997                    ahHandles[cHandles] = pWorker->hProcess;
     998                }
     999                cHandles++;
     1000            }
     1001        if (cHandles == 0)
     1002            return;
     1003
     1004        /*
     1005         * Wait for the processes.
     1006         */
     1007        for (;;)
     1008        {
     1009            DWORD cMsElapsed = GetTickCount() - msStartTick;
     1010            DWORD dwWait = WaitForMultipleObjects(cHandles <= MAXIMUM_WAIT_OBJECTS ? cHandles : MAXIMUM_WAIT_OBJECTS,
     1011                                                  ahHandles, FALSE /*bWaitAll*/,
     1012                                                  cMsElapsed < 1000 ? 1000 - cMsElapsed + 16 : 16);
     1013            if (   dwWait >= WAIT_OBJECT_0
     1014                && dwWait <= WAIT_OBJECT_0 + MAXIMUM_WAIT_OBJECTS)
     1015            {
     1016                size_t idx = dwWait - WAIT_OBJECT_0;
     1017                CloseHandle(apWorkers[idx]->hProcess);
     1018                apWorkers[idx]->hProcess = INVALID_HANDLE_VALUE;
     1019
     1020                if (cHandles <= MAXIMUM_WAIT_OBJECTS)
     1021                {
     1022                    /* Restart the wait with the worker removed, or quit if it was the last worker. */
     1023                    cHandles--;
     1024                    if (!cHandles)
     1025                        return;
     1026                    if (idx != cHandles)
     1027                    {
     1028                        apWorkers[idx] = apWorkers[cHandles];
     1029                        ahHandles[idx] = ahHandles[cHandles];
     1030                    }
     1031                    continue;
     1032                }
     1033                /* else: Reconstruct the wait array so we get maximum coverage. */
     1034            }
     1035            else if (dwWait == WAIT_TIMEOUT)
     1036            {
     1037                /* Terminate the whole bunch. */
     1038                cKillRaids++;
     1039                if (cKillRaids <= 2)
     1040                {
     1041                    fprintf(stderr, "kmk/kSubmit: Killing %u lingering worker processe(s)!\n", cHandles);
     1042                    for (pWorker = g_IdleList.pHead; pWorker != NULL; pWorker = pWorker->pNext)
     1043                        if (pWorker->hProcess != INVALID_HANDLE_VALUE)
     1044                            TerminateProcess(pWorker->hProcess, WAIT_TIMEOUT);
     1045                    for (pWorker = g_BusyList.pHead; pWorker != NULL; pWorker = pWorker->pNext)
     1046                        if (pWorker->hProcess != INVALID_HANDLE_VALUE)
     1047                            TerminateProcess(pWorker->hProcess, WAIT_TIMEOUT);
     1048                }
     1049                else
     1050                {
     1051                    fprintf(stderr, "kmk/kSubmit: Giving up on the last %u worker processe(s). :-(\n", cHandles);
     1052                    break;
     1053                }
     1054            }
     1055            else
     1056            {
     1057                /* Some kind of wait error.  Could be a bad handle, check each and remove
     1058                   bad ones as well as completed ones. */
     1059                size_t idx;
     1060                fprintf(stderr, "kmk/kSubmit: WaitForMultipleObjects unexpectedly returned %#u (err=%u)\n",
     1061                        dwWait, GetLastError());
     1062                for (idx = 0; idx < cHandles; idx++)
     1063                {
     1064                    dwWait = WaitForSingleObject(ahHandles[idx], 0 /*ms*/);
     1065                    if (dwWait != WAIT_TIMEOUT)
     1066                    {
     1067                        CloseHandle(apWorkers[idx]->hProcess);
     1068                        apWorkers[idx]->hProcess = INVALID_HANDLE_VALUE;
     1069                    }
     1070                }
     1071            }
     1072            break;
     1073        } /* wait loop */
     1074    } /* outer wait loop */
     1075}
     1076
    6561077
    6571078
     
    8811302
    8821303
    883 int kmk_builtin_kSubmit(int argc, char **argv, char **envp, struct child *pChild)
     1304int kmk_builtin_kSubmit(int argc, char **argv, char **envp, struct child *pChild, pid_t *pPidSpawned)
    8841305{
    8851306    int             rcExit = 0;
     
    10531474
    10541475                    case 'V':
    1055                         printf("kmk_submit - kBuild version %d.%d.%d (r%u)\n"
    1056                                "Copyright (C) 2007-2016 knut st. osmundsen\n",
    1057                                KBUILD_VERSION_MAJOR, KBUILD_VERSION_MINOR, KBUILD_VERSION_PATCH,
    1058                                KBUILD_SVN_REV);
    1059                         return 0;
     1476                        return kbuild_version(argv[0]);
    10601477                }
    10611478            } while ((chOpt = *pszArg++) != '\0');
     
    10781495        if (pWorker)
    10791496        {
    1080             rcExit = kSubmitSendJobMessage(pWorker, pvMsg, cbMsg, cVerbosity);
     1497            rcExit = kSubmitSendJobMessage(pWorker, pvMsg, cbMsg, 0 /*fNoRespawning*/, cVerbosity);
    10811498            if (rcExit == 0)
    1082             {
    1083                 pWorker->pBusyWith = pChild;
    1084                 /** @todo integrate with sub_proc.c / whatever. */
    1085             }
     1499                rcExit = kSubmitMarkActive(pWorker, cVerbosity, pChild, pPidSpawned);
     1500
     1501            if (!g_fAtExitRegistered)
     1502                if (atexit(kSubmitAtExitCallback) == 0)
     1503                    g_fAtExitRegistered = 1;
    10861504        }
    10871505        else
  • trunk/src/kmk/w32/include/sub_proc.h

    r2591 r2843  
    3939EXTERN_DECL(long process_pipe_io, (HANDLE proc, char *stdin_data,
    4040        int stdin_data_len));
     41#ifndef KMK /* unused */
    4142EXTERN_DECL(long process_file_io, (HANDLE proc));
     43#endif
    4244EXTERN_DECL(void process_cleanup, (HANDLE proc));
    4345EXTERN_DECL(HANDLE process_wait_for_any, (VOID_DECL));
     
    4648EXTERN_DECL(BOOL process_kill, (HANDLE proc, int signal));
    4749EXTERN_DECL(int process_used_slots, (VOID_DECL));
     50#ifdef KMK
     51EXTERN_DECL(int process_kmk_register_submit, (HANDLE hEvent, intptr_t clue));
     52#endif
    4853
    4954/* support routines */
  • trunk/src/kmk/w32/subproc/sub_proc.c

    r2636 r2843  
    2727#include <signal.h>
    2828#include <windows.h>
     29#ifdef KMK
     30# include <assert.h>
     31# include "make.h"
     32# include "kmkbuiltin.h"
     33#endif
     34
    2935
    3036#include "sub_proc.h"
     
    3440
    3541static char *make_command_line(char *shell_name, char *exec_path, char **argv);
     42#ifndef KMK
    3643extern char *xmalloc (unsigned int);
    37 #ifdef KMK
     44#else
    3845extern void kmk_cache_exec_image(const char *); /* imagecache.c */
    3946#endif
    4047
    4148typedef struct sub_process_t {
     49#ifdef KMK
     50        enum { kRegular = 0, kSubmit, kSubProcFreed } enmType;
     51        intptr_t clue;
     52#endif
    4253        intptr_t sv_stdin[2];
    4354        intptr_t sv_stdout[2];
     
    6475static int fake_exits_pending = 0;
    6576
     77#ifndef KMK /* Inefficient! */
    6678/*
    6779 * When a process has been waited for, adjust the wait state
     
    88100        }
    89101}
     102#endif /* !KMK */
    90103
    91104/*
     
    112125        /* wait for someone to exit */
    113126        if (!fake_exits_pending) {
     127#ifdef KMK
     128l_wait_again:
     129#endif
    114130                retval = WaitForMultipleObjects(proc_index, handles, FALSE, INFINITE);
    115131                which = retval - WAIT_OBJECT_0;
     
    123139        if (retval != WAIT_FAILED) {
    124140                sub_process* pproc = proc_array[which];
     141#ifdef KMK
     142                if (pproc->enmType == kSubmit) {
     143                    /* Try get the result from kSubmit.c.  This may not succeed if the whole
     144                       result hasn't arrived yet, in which we just restart the wait. */
     145                    if (kSubmitSubProcGetResult(pproc->clue, &pproc->exit_code, &pproc->signal) != 0) {
     146                        goto l_wait_again;
     147                    }
     148                }
     149#endif
     150#ifndef KMK /* Inefficient! */
    125151                process_adjust_wait_state(pproc);
     152#else
     153                proc_index--;
     154                if ((int)which < proc_index)
     155                        proc_array[which] = proc_array[proc_index];
     156                proc_array[proc_index] = NULL;
     157#endif
    126158                return pproc;
    127159        } else
     
    133165 */
    134166BOOL
    135 process_kill(HANDLE proc, int signal)
     167 process_kill(HANDLE proc, int signal)
    136168{
    137169        sub_process* pproc = (sub_process*) proc;
    138170        pproc->signal = signal;
     171#ifdef KMK
     172        if (pproc->enmType == kRegular) {
     173#endif
    139174        return (TerminateProcess((HANDLE) pproc->pid, signal));
     175#ifdef KMK
     176        } else if (pproc->enmType == kSubmit) {
     177                return kSubmitSubProcKill(pproc->clue, signal) == 0;
     178        }
     179        assert(0);
     180        return FALSE;
     181#endif
    140182}
    141183
     
    149191process_register(HANDLE proc)
    150192{
     193#ifdef KMK
     194        assert(((sub_process *)proc)->enmType == kRegular);
     195#endif
    151196        if (proc_index < MAXIMUM_WAIT_OBJECTS)
    152197                proc_array[proc_index++] = (sub_process *) proc;
    153198}
     199
     200#ifdef KMK
     201/**
     202 * Interface used by kmkbuiltin/kSubmit.c to register stuff going down in a
     203 * worker process.
     204 *
     205 * @returns 0 on success, -1 if there are too many sub-processes already.
     206 * @param   hEvent              The event semaphore to wait on.
     207 * @param   clue                The clue to base.
     208 */
     209int
     210process_kmk_register_submit(HANDLE hEvent, intptr_t clue)
     211{
     212        if (proc_index < MAXIMUM_WAIT_OBJECTS) {
     213                sub_process *pSubProc = (sub_process *)xcalloc(sizeof(*pSubProc));
     214                pSubProc->enmType = kSubmit;
     215                pSubProc->clue    = clue;
     216                pSubProc->pid     = (intptr_t)hEvent;
     217
     218                proc_array[proc_index++] = pSubProc;
     219                return 0;
     220        }
     221        return -1;
     222}
     223#endif
    154224
    155225/*
     
    197267                 */
    198268#ifdef KMK
    199                 (void) process_file_io_private(pproc, FALSE);
     269                if (pproc->enmType == kRegular) {
     270                    (void)process_file_io_private(pproc, FALSE);
     271                }
    200272#else
    201273                (void) process_file_io(pproc);
     
    445517#ifdef KMK
    446518        size_t exec_path_len;
     519
     520        assert (pproc->enmType == kRegular);
    447521#endif
    448522
     
    783857        bool_t child_dead = FALSE;
    784858        BOOL GetExitCodeResult;
     859#ifdef KMK
     860        assert (pproc->enmType == kRegular);
     861#endif
    785862
    786863        /*
     
    918995}
    919996
     997#ifndef KMK /* unused */
    920998/*
    921999 * Purpose: collects output from child process and returns results
     
    9431021        return process_file_io_private(proc, TRUE);
    9441022}
     1023#endif /* !KMK - unused */
    9451024
    9461025/* private function, avoid some kernel calls. (bird) */
     
    10241103        int i;
    10251104
     1105#ifdef KMK
     1106        if (pproc->enmType == kRegular) {
     1107#endif
     1108
    10261109        if (pproc->using_pipes) {
    10271110                for (i= 0; i <= 1; i++) {
     
    10361119        if ((HANDLE)pproc->pid)
    10371120                CloseHandle((HANDLE)pproc->pid);
     1121#ifdef KMK
     1122        } else if (pproc->enmType == kSubmit) {
     1123            /* nothing to do. */
     1124        } else {
     1125            assert(0);
     1126            return;
     1127        }
     1128        pproc->enmType = kSubProcFreed;
     1129#endif
    10381130
    10391131        free(pproc);
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