VirtualBox

Changeset 2900 in kBuild


Ignore:
Timestamp:
Sep 9, 2016 2:42:06 PM (9 years ago)
Author:
bird
Message:

output optimizations

Location:
trunk/src
Files:
2 added
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/kWorker/kWorker.c

    r2898 r2900  
    6969 * they are included. */
    7070#define WITH_HASH_MD5_CACHE
     71
     72/** @def WITH_CONSOLE_OUTPUT_BUFFERING
     73 * Enables buffering of all console output as well as removal of annoying
     74 * source file echo by cl.exe. */
     75#define WITH_CONSOLE_OUTPUT_BUFFERING
    7176
    7277
     
    276281typedef KFSWCACHEDFILE *PKFSWCACHEDFILE;
    277282
    278 
    279283#ifdef WITH_HASH_MD5_CACHE
     284
    280285/** Pointer to a MD5 hash instance. */
    281286typedef struct KWHASHMD5 *PKWHASHMD5;
     
    307312/** Magic value for KWHASHMD5::uMagic (Les McCann). */
    308313# define KWHASHMD5_MAGIC    KUPTR_C(0x19350923)
     314
    309315#endif /* WITH_HASH_MD5_CACHE */
    310 
    311 
     316#ifdef WITH_TEMP_MEMORY_FILES
    312317
    313318typedef struct KWFSTEMPFILESEG *PKWFSTEMPFILESEG;
     
    345350} KWFSTEMPFILE;
    346351
     352#endif /* WITH_TEMP_MEMORY_FILES */
     353#ifdef WITH_CONSOLE_OUTPUT_BUFFERING
     354
     355/**
     356 * Console line buffer.
     357 */
     358typedef struct KWCONSOLEOUTPUTLINE
     359{
     360    /** The main output handle. */
     361    HANDLE              hOutput;
     362    /** Our backup handle. */
     363    HANDLE              hBackup;
     364    /** Set if this is a console handle. */
     365    KBOOL               fIsConsole;
     366    /** Amount of pending console output in wchar_t's. */
     367    KU32                cwcBuf;
     368    /** The allocated buffer size.   */
     369    KU32                cwcBufAlloc;
     370    /** Pending console output. */
     371    wchar_t            *pwcBuf;
     372} KWCONSOLEOUTPUTLINE;
     373/** Pointer to a console line buffer. */
     374typedef KWCONSOLEOUTPUTLINE *PKWCONSOLEOUTPUTLINE;
     375
     376/**
     377 * Combined console buffer of complete lines.
     378 */
     379typedef struct KWCONSOLEOUTPUT
     380{
     381    /** The console output handle.
     382     * INVALID_HANDLE_VALUE if we haven't got a console and shouldn't be doing any
     383     * combined output buffering. */
     384    HANDLE              hOutput;
     385    /** The current code page for the console. */
     386    KU32                uCodepage;
     387    /** Amount of pending console output in wchar_t's. */
     388    KU32                cwcBuf;
     389    /** Number of times we've flushed it in any way (for cl.exe hack). */
     390    KU32                cFlushes;
     391    /** Pending console output. */
     392    wchar_t             wszBuf[8192];
     393} KWCONSOLEOUTPUT;
     394/** Pointer to a combined console buffer. */
     395typedef KWCONSOLEOUTPUT *PKWCONSOLEOUTPUT;
     396
     397#endif /* WITH_CONSOLE_OUTPUT_BUFFERING */
    347398
    348399/** Handle type.   */
     
    554605    } LastHashRead;
    555606#endif
     607
     608#ifdef WITH_CONSOLE_OUTPUT_BUFFERING
     609    /** Standard output (and whatever else) line buffer. */
     610    KWCONSOLEOUTPUTLINE StdOut;
     611    /** Standard error line buffer. */
     612    KWCONSOLEOUTPUTLINE StdErr;
     613    /** Combined buffer of completed lines. */
     614    KWCONSOLEOUTPUT     Combined;
     615#endif
    556616} KWSANDBOX;
    557617
     
    640700static int kwLdrModuleResolveAndLookup(const char *pszName, PKWMODULE pExe, PKWMODULE pImporter, PKWMODULE *ppMod);
    641701static KBOOL kwSandboxHandleTableEnter(PKWSANDBOX pSandbox, PKWHANDLE pHandle);
     702#ifdef WITH_CONSOLE_OUTPUT_BUFFERING
     703static void kwSandboxConsoleWriteA(PKWSANDBOX pSandbox, PKWCONSOLEOUTPUTLINE pLineBuf, const char *pchBuffer, KU32 cchToWrite);
     704#endif
    642705
    643706
     
    50135076    }
    50145077
     5078#ifdef WITH_CONSOLE_OUTPUT_BUFFERING
     5079    /*
     5080     * Check for stdout and stderr.
     5081     */
     5082    if (   g_Sandbox.StdErr.hOutput == hFile
     5083        || g_Sandbox.StdOut.hOutput == hFile)
     5084    {
     5085        PKWCONSOLEOUTPUTLINE pLineBuf = g_Sandbox.StdErr.hOutput == hFile ? &g_Sandbox.StdErr : &g_Sandbox.StdOut;
     5086        if (pLineBuf->fIsConsole)
     5087        {
     5088            kwSandboxConsoleWriteA(&g_Sandbox, pLineBuf, (const char *)pvBuffer, cbToWrite);
     5089            KWFS_LOG(("WriteFile(console) -> TRUE\n", hFile));
     5090            return TRUE;
     5091        }
     5092    }
     5093#endif
     5094
    50155095    KWFS_LOG(("WriteFile(%p)\n", hFile));
    50165096    return WriteFile(hFile, pvBuffer, cbToWrite, pcbActuallyWritten, pOverlapped);
     
    54995579}
    55005580#endif /* WITH_TEMP_MEMORY_FILES */
     5581
     5582
     5583
     5584#ifdef WITH_CONSOLE_OUTPUT_BUFFERING
     5585
     5586/*
     5587 *
     5588 * Console output buffering.
     5589 * Console output buffering.
     5590 * Console output buffering.
     5591 *
     5592 */
     5593
     5594
     5595/**
     5596 * Write a wide char string to the console.
     5597 *
     5598 * @param   pSandbox            The sandbox which output buffer to flush.
     5599 */
     5600static void kwSandboxConsoleWriteIt(PKWSANDBOX pSandbox, wchar_t const *pwcBuf, KU32 cwcToWrite)
     5601{
     5602    if (cwcToWrite > 0)
     5603    {
     5604        DWORD cwcWritten = 0;
     5605        if (WriteConsoleW(pSandbox->Combined.hOutput, pwcBuf, cwcToWrite, &cwcWritten, NULL))
     5606        {
     5607            if (cwcWritten == cwcToWrite)
     5608            { /* likely */ }
     5609            else
     5610            {
     5611                DWORD off = 0;
     5612                do
     5613                {
     5614                    off += cwcWritten;
     5615                    cwcWritten = 0;
     5616                }
     5617                while (   off < cwcToWrite
     5618                       && WriteConsoleW(pSandbox->Combined.hOutput, &pwcBuf[off], cwcToWrite - off, &cwcWritten, NULL));
     5619                kHlpAssert(off == cwcWritten);
     5620            }
     5621        }
     5622        else
     5623            kHlpAssertFailed();
     5624        pSandbox->Combined.cFlushes++;
     5625    }
     5626}
     5627
     5628
     5629/**
     5630 * Flushes the combined console output buffer.
     5631 *
     5632 * @param   pSandbox            The sandbox which output buffer to flush.
     5633 */
     5634static void kwSandboxConsoleFlushCombined(PKWSANDBOX pSandbox)
     5635{
     5636    if (pSandbox->Combined.cwcBuf > 0)
     5637    {
     5638        kwSandboxConsoleWriteIt(pSandbox, pSandbox->Combined.wszBuf, pSandbox->Combined.cwcBuf);
     5639        pSandbox->Combined.cwcBuf = 0;
     5640    }
     5641}
     5642
     5643
     5644/**
     5645 * For handling combined buffer overflow cases line by line.
     5646 *
     5647 * @param   pSandbox            The sandbox.
     5648 * @param   pwcBuf              What to add to the combined buffer.  Usually a
     5649 *                              line, unless we're really low on buffer space.
     5650 * @param   cwcBuf              The length of what to add.
     5651 * @param   fBrokenLine         Whether this is a broken line.
     5652 */
     5653static void kwSandboxConsoleAddToCombined(PKWSANDBOX pSandbox, wchar_t const *pwcBuf, KU32 cwcBuf, KBOOL fBrokenLine)
     5654{
     5655    if (fBrokenLine)
     5656        kwSandboxConsoleFlushCombined(pSandbox);
     5657    if (pSandbox->Combined.cwcBuf + cwcBuf > K_ELEMENTS(pSandbox->Combined.wszBuf))
     5658    {
     5659        kwSandboxConsoleFlushCombined(pSandbox);
     5660        kwSandboxConsoleWriteIt(pSandbox, pwcBuf, cwcBuf);
     5661    }
     5662    else
     5663    {
     5664        memcpy(&pSandbox->Combined.wszBuf[pSandbox->Combined.cwcBuf], pwcBuf, cwcBuf * sizeof(wchar_t));
     5665        pSandbox->Combined.cwcBuf += cwcBuf;
     5666    }
     5667}
     5668
     5669
     5670/**
     5671 * Called to final flush a line buffer via the combined buffer (if applicable).
     5672 *
     5673 * @param   pSandbox            The sandbox.
     5674 * @param   pLineBuf            The line buffer.
     5675 */
     5676static void kwSandboxConsoleFinalFlushLineBuf(PKWSANDBOX pSandbox, PKWCONSOLEOUTPUTLINE pLineBuf)
     5677{
     5678    if (pLineBuf->cwcBuf > 0)
     5679    {
     5680        if (pLineBuf->fIsConsole)
     5681        {
     5682            if (pLineBuf->cwcBuf < pLineBuf->cwcBufAlloc)
     5683            {
     5684                pLineBuf->pwcBuf[pLineBuf->cwcBuf++] = '\n';
     5685                kwSandboxConsoleAddToCombined(pSandbox, pLineBuf->pwcBuf, pLineBuf->cwcBuf, K_FALSE /*fBrokenLine*/);
     5686            }
     5687            else
     5688            {
     5689                kwSandboxConsoleAddToCombined(pSandbox, pLineBuf->pwcBuf, pLineBuf->cwcBuf, K_TRUE /*fBrokenLine*/);
     5690                kwSandboxConsoleAddToCombined(pSandbox, L"\n", 1, K_TRUE /*fBrokenLine*/);
     5691            }
     5692            pLineBuf->cwcBuf = 0;
     5693        }
     5694        else
     5695        {
     5696            kHlpAssertFailed();
     5697        }
     5698    }
     5699}
     5700
     5701
     5702/**
     5703 * Called at the end of sandboxed execution to flush both stream buffers.
     5704 *
     5705 * @param   pSandbox            The sandbox.
     5706 */
     5707static void kwSandboxConsoleFlushAll(PKWSANDBOX pSandbox)
     5708{
     5709    /*
     5710     * First do the cl.exe source file supression trick, if applicable.
     5711     */
     5712    if (   pSandbox->Combined.cwcBuf >= 3
     5713        && pSandbox->StdOut.cwcBuf == 0
     5714        && pSandbox->StdErr.cwcBuf == 0
     5715        && pSandbox->Combined.cFlushes == 0
     5716        && pSandbox->pTool->u.Sandboxed.enmHint == KWTOOLHINT_VISUAL_CPP_CL)
     5717    {
     5718        KI32    off = pSandbox->Combined.cwcBuf - 1;
     5719        if (pSandbox->Combined.wszBuf[off] == '\n')
     5720        {
     5721            KBOOL fOk = K_TRUE;
     5722            while (off-- > 0)
     5723            {
     5724                wchar_t const wc = pSandbox->Combined.wszBuf[off];
     5725                if (iswalnum(wc) || wc == '.' || wc == ' ' || wc == '_' || wc == '-')
     5726                { /* likely */ }
     5727                else
     5728                {
     5729                    fOk = K_FALSE;
     5730                    break;
     5731                }
     5732            }
     5733            if (fOk)
     5734            {
     5735                pSandbox->Combined.cwcBuf = 0;
     5736                return;
     5737            }
     5738        }
     5739    }
     5740
     5741    /*
     5742     * Flush the two line buffer, the the combined buffer.
     5743     */
     5744    kwSandboxConsoleFinalFlushLineBuf(pSandbox, &pSandbox->StdErr);
     5745    kwSandboxConsoleFinalFlushLineBuf(pSandbox, &pSandbox->StdOut);
     5746    kwSandboxConsoleFlushCombined(pSandbox);
     5747}
     5748
     5749
     5750/**
     5751 * Writes a string to the given output stream.
     5752 *
     5753 * @param   pSandbox            The sandbox.
     5754 * @param   pLineBuf            The line buffer for the output stream.
     5755 * @param   pwcBuffer           The buffer to write.
     5756 * @param   cwcToWrite          The number of wchar_t's in the buffer.
     5757 */
     5758static void kwSandboxConsoleWriteW(PKWSANDBOX pSandbox, PKWCONSOLEOUTPUTLINE pLineBuf, wchar_t const *pwcBuffer, KU32 cwcToWrite)
     5759{
     5760    if (cwcToWrite > 0)
     5761    {
     5762        /*
     5763         * First, find the start of the last incomplete line so we can figure
     5764         * out how much line buffering we need to do.
     5765         */
     5766        KU32 cchLastIncompleteLine;
     5767        KU32 offLastIncompleteLine = cwcToWrite;
     5768        while (   offLastIncompleteLine > 0
     5769               && pwcBuffer[offLastIncompleteLine - 1] != '\n')
     5770            offLastIncompleteLine--;
     5771        cchLastIncompleteLine = cwcToWrite - offLastIncompleteLine;
     5772
     5773        /* Was there anything to line buffer? */
     5774        if (offLastIncompleteLine < cwcToWrite)
     5775        {
     5776            /* Need to grow the line buffer? */
     5777            KU32 cwcNeeded = offLastIncompleteLine != 0 ? offLastIncompleteLine : cchLastIncompleteLine + pLineBuf->cwcBuf;
     5778            if (cwcNeeded > pLineBuf->cwcBufAlloc)
     5779            {
     5780                void *pvNew;
     5781                KU32  cwcNew = !pLineBuf->cwcBufAlloc ? 1024 : pLineBuf->cwcBufAlloc * 2;
     5782                while (cwcNew < cwcNeeded)
     5783                    cwcNew *= 2;
     5784                pvNew = kHlpRealloc(pLineBuf->pwcBuf, cwcNew * sizeof(wchar_t));
     5785                if (pvNew)
     5786                {
     5787                    pLineBuf->pwcBuf = (wchar_t *)pvNew;
     5788                    pLineBuf->cwcBufAlloc = cwcNew;
     5789                }
     5790                else
     5791                {
     5792                    pvNew = kHlpRealloc(pLineBuf->pwcBuf, cwcNeeded * sizeof(wchar_t));
     5793                    if (pvNew)
     5794                    {
     5795                        pLineBuf->pwcBuf = (wchar_t *)pvNew;
     5796                        pLineBuf->cwcBufAlloc = cwcNeeded;
     5797                    }
     5798                    else
     5799                    {
     5800                        /* This isn't perfect, but it will have to do for now. */
     5801                        if (pLineBuf->cwcBuf > 0)
     5802                        {
     5803                            kwSandboxConsoleAddToCombined(pSandbox, pLineBuf->pwcBuf, pLineBuf->cwcBuf, K_TRUE /*fBrokenLine*/);
     5804                            pLineBuf->cwcBuf = 0;
     5805                        }
     5806                        kwSandboxConsoleAddToCombined(pSandbox, pwcBuffer, cwcToWrite, K_TRUE /*fBrokenLine*/);
     5807                        return;
     5808                    }
     5809                }
     5810            }
     5811
     5812            /*
     5813             * Handle the case where we only add to the line buffer.
     5814             */
     5815            if (offLastIncompleteLine == 0)
     5816            {
     5817                memcpy(&pLineBuf->pwcBuf[pLineBuf->cwcBuf], pwcBuffer, cwcToWrite * sizeof(wchar_t));
     5818                pLineBuf->cwcBuf += cwcToWrite;
     5819                return;
     5820            }
     5821        }
     5822
     5823        /*
     5824         * If there is sufficient combined buffer to handle this request, this are rather simple.
     5825         */
     5826        if (pLineBuf->cwcBuf + cchLastIncompleteLine <= K_ELEMENTS(pSandbox->Combined.wszBuf))
     5827        {
     5828            if (pLineBuf->cwcBuf > 0)
     5829            {
     5830                memcpy(&pSandbox->Combined.wszBuf[pSandbox->Combined.cwcBuf],
     5831                       pLineBuf->pwcBuf, pLineBuf->cwcBuf * sizeof(wchar_t));
     5832                pSandbox->Combined.cwcBuf += pLineBuf->cwcBuf;
     5833                pLineBuf->cwcBuf = 0;
     5834            }
     5835
     5836            memcpy(&pSandbox->Combined.wszBuf[pSandbox->Combined.cwcBuf],
     5837                   pwcBuffer, offLastIncompleteLine * sizeof(wchar_t));
     5838            pSandbox->Combined.cwcBuf += offLastIncompleteLine;
     5839        }
     5840        else
     5841        {
     5842            /*
     5843             * Do line-by-line processing of the input, flusing the combined buffer
     5844             * when it becomes necessary.  We may have to write lines
     5845             */
     5846            KU32 off = 0;
     5847            KU32 offNextLine = 0;
     5848
     5849            /* If there is buffered chars, we handle the first line outside the
     5850               main loop.  We must try our best outputting it as a complete line. */
     5851            if (pLineBuf->cwcBuf > 0)
     5852            {
     5853                while (offNextLine < cwcToWrite && pwcBuffer[offNextLine] != '\n')
     5854                    offNextLine++;
     5855                offNextLine++;
     5856                kHlpAssert(offNextLine <= offLastIncompleteLine);
     5857
     5858                if (pLineBuf->cwcBuf + offNextLine + pSandbox->Combined.cwcBuf <= K_ELEMENTS(pSandbox->Combined.wszBuf))
     5859                {
     5860                    memcpy(&pSandbox->Combined.wszBuf[pSandbox->Combined.cwcBuf],
     5861                           pLineBuf->pwcBuf, pLineBuf->cwcBuf * sizeof(wchar_t));
     5862                    pSandbox->Combined.cwcBuf += pLineBuf->cwcBuf;
     5863                    pLineBuf->cwcBuf = 0;
     5864
     5865                    memcpy(&pSandbox->Combined.wszBuf[pSandbox->Combined.cwcBuf], pwcBuffer, offNextLine * sizeof(wchar_t));
     5866                    pSandbox->Combined.cwcBuf += offNextLine;
     5867                }
     5868                else
     5869                {
     5870                    KU32 cwcLeft = pLineBuf->cwcBufAlloc - pLineBuf->cwcBuf;
     5871                    if (cwcLeft > 0)
     5872                    {
     5873                        KU32 cwcCopy = K_MIN(cwcLeft, offNextLine);
     5874                        memcpy(&pLineBuf->pwcBuf[pLineBuf->cwcBuf], pwcBuffer, cwcCopy * sizeof(wchar_t));
     5875                        pLineBuf->cwcBuf += cwcCopy;
     5876                        off += cwcCopy;
     5877                    }
     5878                    if (pLineBuf->cwcBuf > 0)
     5879                    {
     5880                        kwSandboxConsoleAddToCombined(pSandbox, pLineBuf->pwcBuf, pLineBuf->cwcBuf, K_TRUE /*fBrokenLine*/);
     5881                        pLineBuf->cwcBuf = 0;
     5882                    }
     5883                    if (off < offNextLine)
     5884                        kwSandboxConsoleAddToCombined(pSandbox, &pwcBuffer[off], offNextLine - off, K_TRUE /*fBrokenLine*/);
     5885                }
     5886                off = offNextLine;
     5887            }
     5888
     5889            /* Deal with the remaining lines */
     5890            while (off < offLastIncompleteLine)
     5891            {
     5892                while (offNextLine < offLastIncompleteLine && pwcBuffer[offNextLine] != '\n')
     5893                    offNextLine++;
     5894                offNextLine++;
     5895                kHlpAssert(offNextLine <= offLastIncompleteLine);
     5896                kwSandboxConsoleAddToCombined(pSandbox, &pwcBuffer[off], offNextLine - off, K_FALSE /*fBrokenLine*/);
     5897                off = offNextLine;
     5898            }
     5899        }
     5900
     5901        /*
     5902         * Buffer any remaining incomplete line chars.
     5903         */
     5904        if (offLastIncompleteLine < cwcToWrite)
     5905        {
     5906            memcpy(&pLineBuf->pwcBuf, &pwcBuffer[offLastIncompleteLine], cchLastIncompleteLine * sizeof(wchar_t));
     5907            pLineBuf->cwcBuf = cchLastIncompleteLine;
     5908        }
     5909    }
     5910}
     5911
     5912
     5913/**
     5914 * Worker for WriteConsoleA and WriteFile.
     5915 *
     5916 * @param   pSandbox            The sandbox.
     5917 * @param   pLineBuf            The line buffer.
     5918 * @param   pchBuffer           What to write.
     5919 * @param   cchToWrite          How much to write.
     5920 */
     5921static void kwSandboxConsoleWriteA(PKWSANDBOX pSandbox, PKWCONSOLEOUTPUTLINE pLineBuf, const char *pchBuffer, KU32 cchToWrite)
     5922{
     5923    /*
     5924     * Convert it to wide char and use the 'W' to do the work.
     5925     */
     5926    int         cwcRet;
     5927    KU32        cwcBuf = cchToWrite * 2 + 1;
     5928    wchar_t    *pwcBufFree = NULL;
     5929    wchar_t    *pwcBuf;
     5930
     5931    if (cwcBuf <= 4096)
     5932        pwcBuf = alloca(cwcBuf * sizeof(wchar_t));
     5933    else
     5934        pwcBuf = pwcBufFree = kHlpAlloc(cwcBuf * sizeof(wchar_t));
     5935
     5936    cwcRet = MultiByteToWideChar(pSandbox->Combined.uCodepage, 0/*dwFlags*/, pchBuffer, cchToWrite, pwcBuf, cwcBuf);
     5937    if (cwcRet > 0)
     5938         kwSandboxConsoleWriteW(pSandbox, pLineBuf, pwcBuf, cwcRet);
     5939    else
     5940    {
     5941        DWORD cchWritten;
     5942        kHlpAssertFailed();
     5943
     5944        /* Flush the line buffer and combined buffer before calling WriteConsoleA. */
     5945        if (pLineBuf->cwcBuf > 0)
     5946        {
     5947            kwSandboxConsoleAddToCombined(pSandbox, pLineBuf->pwcBuf, pLineBuf->cwcBuf, K_TRUE /*fBroken*/);
     5948            pLineBuf->cwcBuf = 0;
     5949        }
     5950        kwSandboxConsoleFlushCombined(pSandbox);
     5951
     5952        if (WriteConsoleA(pLineBuf->hBackup, pchBuffer, cchToWrite, &cchWritten, NULL /*pvReserved*/))
     5953        {
     5954            if (cchWritten >= cchToWrite)
     5955            { /* likely */ }
     5956            else
     5957            {
     5958                KU32 off = 0;
     5959                do
     5960                {
     5961                    off += cchWritten;
     5962                    cchWritten = 0;
     5963                } while (   off < cchToWrite
     5964                         && WriteConsoleA(pLineBuf->hBackup, &pchBuffer[off], cchToWrite - off, &cchWritten, NULL));
     5965            }
     5966        }
     5967    }
     5968
     5969    if (pwcBufFree)
     5970        kHlpFree(pwcBufFree);
     5971}
     5972
     5973
     5974/** Kernel32 - WriteConsoleA  */
     5975BOOL WINAPI kwSandbox_Kernel32_WriteConsoleA(HANDLE hConOutput, CONST VOID *pvBuffer, DWORD cbToWrite, PDWORD pcbWritten,
     5976                                             PVOID pvReserved)
     5977{
     5978    BOOL                    fRc;
     5979    PKWCONSOLEOUTPUTLINE    pLineBuf;
     5980
     5981    if (hConOutput == g_Sandbox.StdErr.hOutput)
     5982        pLineBuf = &g_Sandbox.StdErr;
     5983    else
     5984        pLineBuf = &g_Sandbox.StdOut;
     5985    if (pLineBuf->fIsConsole)
     5986    {
     5987        kwSandboxConsoleWriteA(&g_Sandbox, pLineBuf, (char const *)pvBuffer, cbToWrite);
     5988
     5989        KWFS_LOG(("WriteConsoleA: %p, %p LB %#x (%*.*s), %p, %p -> TRUE [cached]\n",
     5990                  hConOutput, pvBuffer, cbToWrite, cbToWrite, cbToWrite, pvBuffer, pcbWritten, pvReserved));
     5991        if (pcbWritten)
     5992            *pcbWritten = cbToWrite;
     5993        fRc = TRUE;
     5994    }
     5995    else
     5996    {
     5997        fRc = WriteConsoleA(hConOutput, pvBuffer, cbToWrite, pcbWritten, pvReserved);
     5998        KWFS_LOG(("WriteConsoleA: %p, %p LB %#x (%*.*s), %p, %p -> %d !fallback!\n",
     5999                  hConOutput, pvBuffer, cbToWrite, cbToWrite, cbToWrite, pvBuffer, pcbWritten, pvReserved, fRc));
     6000    }
     6001    return fRc;
     6002}
     6003
     6004
     6005/** Kernel32 - WriteConsoleW  */
     6006BOOL WINAPI kwSandbox_Kernel32_WriteConsoleW(HANDLE hConOutput, CONST VOID *pvBuffer, DWORD cwcToWrite, PDWORD pcwcWritten,
     6007                                             PVOID pvReserved)
     6008{
     6009    BOOL                    fRc;
     6010    PKWCONSOLEOUTPUTLINE    pLineBuf;
     6011
     6012    if (hConOutput == g_Sandbox.StdErr.hOutput)
     6013        pLineBuf = &g_Sandbox.StdErr;
     6014    else
     6015        pLineBuf = &g_Sandbox.StdOut;
     6016    if (pLineBuf->fIsConsole)
     6017    {
     6018        kwSandboxConsoleWriteW(&g_Sandbox, pLineBuf, (wchar_t const *)pvBuffer, cwcToWrite);
     6019
     6020        KWFS_LOG(("WriteConsoleW: %p, %p LB %#x (%*.*ls), %p, %p -> TRUE [cached]\n",
     6021                  hConOutput, pvBuffer, cwcToWrite, cwcToWrite, cwcToWrite, pvBuffer, pcwcWritten, pvReserved));
     6022        if (pcwcWritten)
     6023            *pcwcWritten = cwcToWrite;
     6024        fRc = TRUE;
     6025    }
     6026    else
     6027    {
     6028        fRc = WriteConsoleW(hConOutput, pvBuffer, cwcToWrite, pcwcWritten, pvReserved);
     6029        KWFS_LOG(("WriteConsoleW: %p, %p LB %#x (%*.*ls), %p, %p -> %d !fallback!\n",
     6030                  hConOutput, pvBuffer, cwcToWrite, cwcToWrite, cwcToWrite, pvBuffer, pcwcWritten, pvReserved, fRc));
     6031    }
     6032    return fRc;
     6033}
     6034
     6035#endif /* WITH_CONSOLE_OUTPUT_BUFFERING */
    55016036
    55026037
     
    61276662#endif
    61286663
     6664    { TUPLE("WriteConsoleA"),               NULL,       (KUPTR)kwSandbox_Kernel32_WriteConsoleA },
     6665    { TUPLE("WriteConsoleW"),               NULL,       (KUPTR)kwSandbox_Kernel32_WriteConsoleW },
     6666
    61296667    { TUPLE("VirtualAlloc"),                NULL,       (KUPTR)kwSandbox_Kernel32_VirtualAlloc },
    61306668    { TUPLE("VirtualFree"),                 NULL,       (KUPTR)kwSandbox_Kernel32_VirtualFree },
     
    62416779    { TUPLE("SetConsoleCtrlHandler"),       NULL,       (KUPTR)kwSandbox_Kernel32_SetConsoleCtrlHandler },
    62426780
     6781    { TUPLE("WriteConsoleA"),               NULL,       (KUPTR)kwSandbox_Kernel32_WriteConsoleA },
     6782    { TUPLE("WriteConsoleW"),               NULL,       (KUPTR)kwSandbox_Kernel32_WriteConsoleW },
     6783
    62436784#ifdef WITH_HASH_MD5_CACHE
    62446785    { TUPLE("CryptCreateHash"),             NULL,       (KUPTR)kwSandbox_Advapi32_CryptCreateHash },
     
    65537094    pSandbox->pgmptr        = (char *)pTool->pszPath;
    65547095    pSandbox->wpgmptr       = (wchar_t *)pTool->pwszPath;
     7096#ifdef WITH_CONSOLE_OUTPUT_BUFFERING
     7097    pSandbox->StdOut.cwcBuf = 0;
     7098    pSandbox->StdErr.cwcBuf = 0;
     7099    pSandbox->Combined.cwcBuf = 0;
     7100    pSandbox->Combined.cFlushes = 0;
     7101#endif
    65557102    pSandbox->cArgs         = cArgs;
    65567103    pSandbox->papszArgs     = (char **)papszArgs;
     
    68857432            rcExit = 42 + 4;
    68867433
    6887         /* Clean up essential bits only, the rest is done after we've replied to kmk. */
     7434        /*
     7435         * Flush and clean up the essential bits only, postpone whatever we
     7436         * can till after we've replied to kmk.
     7437         */
     7438#ifdef WITH_CONSOLE_OUTPUT_BUFFERING
     7439        kwSandboxConsoleFlushAll(&g_Sandbox);
     7440#endif
    68887441        kwSandboxCleanup(&g_Sandbox);
    68897442    }
     
    73767929    PVOID           pvVecXcptHandler = AddVectoredExceptionHandler(0 /*called last*/, kwSandboxVecXcptEmulateChained);
    73777930#endif
     7931#ifdef WITH_CONSOLE_OUTPUT_BUFFERING
     7932    HANDLE                          hCurProc       = GetCurrentProcess();
     7933    PPEB                            pPeb           = kwSandboxGetProcessEnvironmentBlock();
     7934    PMY_RTL_USER_PROCESS_PARAMETERS pProcessParams = (PMY_RTL_USER_PROCESS_PARAMETERS)pPeb->ProcessParameters;
     7935#endif
    73787936
    73797937    /*
     
    73997957    if (pszTmp && *pszTmp != '\0')
    74007958        kFsCacheSetupCustomRevisionForTree(g_pFsCache, kFsCacheLookupA(g_pFsCache, pszTmp, &enmIgnored));
     7959
     7960#ifdef WITH_CONSOLE_OUTPUT_BUFFERING
     7961    /*
     7962     * Get and duplicate the console handles.
     7963     */
     7964    g_Sandbox.StdOut.hOutput = pProcessParams->StandardOutput;
     7965    if (!DuplicateHandle(hCurProc, pProcessParams->StandardOutput, hCurProc, &g_Sandbox.StdOut.hBackup,
     7966                         GENERIC_WRITE, FALSE /*fInherit*/, DUPLICATE_SAME_ACCESS))
     7967        kHlpAssertFailedStmt(g_Sandbox.StdOut.hBackup = pProcessParams->StandardOutput);
     7968    g_Sandbox.StdOut.fIsConsole = GetFileType(g_Sandbox.StdOut.hOutput) == FILE_TYPE_CHAR;
     7969
     7970    g_Sandbox.StdErr.hOutput = pProcessParams->StandardError;
     7971    if (!DuplicateHandle(hCurProc, pProcessParams->StandardError, hCurProc, &g_Sandbox.StdErr.hBackup,
     7972                         GENERIC_WRITE, FALSE /*fInherit*/, DUPLICATE_SAME_ACCESS))
     7973        kHlpAssertFailedStmt(g_Sandbox.StdErr.hBackup = pProcessParams->StandardError);
     7974    g_Sandbox.StdErr.fIsConsole = GetFileType(g_Sandbox.StdErr.hOutput) == FILE_TYPE_CHAR;
     7975
     7976    if (g_Sandbox.StdErr.fIsConsole)
     7977    {
     7978        g_Sandbox.Combined.hOutput   = g_Sandbox.StdErr.hBackup;
     7979        g_Sandbox.Combined.uCodepage = GetConsoleCP();
     7980    }
     7981    else if (g_Sandbox.StdOut.fIsConsole)
     7982    {
     7983        g_Sandbox.Combined.hOutput   = g_Sandbox.StdOut.hBackup;
     7984        g_Sandbox.Combined.uCodepage = GetConsoleCP();
     7985    }
     7986    else
     7987    {
     7988        g_Sandbox.Combined.hOutput   = INVALID_HANDLE_VALUE;
     7989        g_Sandbox.Combined.uCodepage = CP_ACP;
     7990    }
     7991#endif
     7992
    74017993
    74027994    /*
  • trunk/src/kmk/kmkbuiltin/cat.c

    r2113 r2900  
    8181
    8282
     83#ifdef KBUILD_OS_WINDOWS
     84/* This is a trick to seriuosly speed up console output windows. */
     85# undef write
     86# define write maybe_con_write
     87extern ssize_t maybe_con_write(int, void const *, size_t);
     88#endif
     89
     90
    8391int bflag, eflag, nflag, sflag, tflag, vflag;
    8492/*int rval;*/
     
    120128#ifdef kmk_builtin_cat /* kmk did this already. */
    121129        setlocale(LC_CTYPE, "");
     130#else
     131        fflush(stdout);
    122132#endif
    123133
     
    288298raw_cat(int rfd)
    289299{
    290         int off, wfd;
     300        int off, wfd = fileno(stdout);
    291301        ssize_t nr, nw;
    292302        static size_t bsize;
     
    298308                if (fstat(wfd, &sbuf))
    299309                        return err(1, "%s", filename);
    300 #ifdef _MSC_VER
    301                 bsize = 1024;
     310#ifdef KBUILD_OS_WINDOWS
     311                bsize = 16384;
    302312#else
    303313                bsize = MAX(sbuf.st_blksize, 1024);
  • trunk/src/kmk/kmkbuiltin/printf.c

    r2646 r2900  
    7676#include "../kmkbuiltin.h"
    7777
     78#ifdef KBUILD_OS_WINDOWS
     79/* This is a trick to speed up console output on windows. */
     80# undef fwrite
     81# define fwrite maybe_con_fwrite
     82extern size_t maybe_con_fwrite(void const *, size_t, size_t, FILE *);
     83#endif
     84
    7885
    7986#ifdef __GNUC__
     
    113120static int       usage(FILE *);
    114121
     122static int      flush_buffer(void);
    115123static void     b_count(int);
    116124static void     b_output(int);
     
    126134#include "../../bin/sh/bltin/bltin.h"
    127135#endif /* SHELL */
     136
     137/* Buffer the output because windows doesn't do line buffering of stdout. */
     138static char     g_achBuf[256];
     139static size_t   g_cchBuf;
    128140
    129141#define PF(f, func) { \
     
    156168        int ch;
    157169
    158         /* kmk: reset getopt and set progname */
     170        /* kmk: reset getopt, set progname and reset buffer. */
    159171        g_progname = argv[0];
    160172        opterr = 1;
     
    225237        rval = 0;
    226238        gargv = NULL;
     239        g_cchBuf = 0;
    227240
    228241        format = *argv;
     
    272285                        ch = *fmt;
    273286                        if (!ch) {
     287                                flush_buffer();
    274288                                warnx("missing format character");
    275289                                return (1);
     
    354368                        }
    355369                        default:
     370                                flush_buffer();
    356371                                warnx("%s: invalid directive", start);
    357372                                return 1;
     
    360375                        *fmt = nextch;
    361376                        /* escape if a \c was encountered */
    362                         if (rval & 0x100)
     377                        if (rval & 0x100) {
     378                                flush_buffer();
    363379                                return rval & ~0x100;
     380                        }
    364381                }
    365382        } while (gargv != argv && *gargv);
    366383
     384        flush_buffer();
    367385        return rval;
    368386}
     387
    369388
    370389/* helper functions for conv_escape_str */
     
    408427        }
    409428#endif
    410         return putchar(ch);
     429        /* Buffered output. */
     430        if (g_cchBuf + 1 < sizeof(g_achBuf)) {
     431                g_achBuf[g_cchBuf++] = ch;
     432        } else {
     433                int rc = flush_buffer();
     434                g_achBuf[g_cchBuf++] = ch;
     435                if (rc)
     436                        return -1;
     437        }
     438        return 0;
    411439}
    412440
    413441static int wrap_printf(const char * fmt, ...)
    414442{
    415         int rc;
     443        ssize_t cchRet;
    416444        va_list va;
    417 
     445        char *pszTmp;
     446
     447        va_start(va, fmt);
     448        cchRet = vasprintf(&pszTmp, fmt, va);
     449        va_end(va);
     450        if (cchRet >= 0) {
    418451#ifndef kmk_builtin_printf
    419         if (g_o) {
    420                 char *str;
    421 
    422                 va_start(va, fmt);
    423                 rc = vasprintf(&str, fmt, va);
    424                 va_end(va);
    425                 if (rc >= 0) {
    426                         g_o = variable_buffer_output(g_o, str, rc);
    427                         free(str);
    428                 }
    429                 return rc;
    430         }
    431 #endif
    432 
    433         va_start(va, fmt);
    434         rc = vprintf(fmt, va);
    435         va_end(va);
    436         return rc;
    437 }
     452                if (g_o) {
     453                        g_o = variable_buffer_output(g_o, pszTmp, cchRet);
     454                } else
     455#endif
     456                {
     457                        if (cchRet + g_cchBuf <= sizeof(g_achBuf)) {
     458                                /* We've got space in the buffer. */
     459                                memcpy(&g_achBuf[g_cchBuf], pszTmp, cchRet);
     460                                g_cchBuf += cchRet;
     461                        } else {
     462                                /* Try write out complete lines. */
     463                                const char *pszLeft = pszTmp;
     464                                ssize_t     cchLeft = cchRet;
     465
     466                                while (cchLeft > 0) {
     467                                        const char *pchNewLine = strchr(pszLeft, '\n');
     468                                        ssize_t     cchLine    = pchNewLine ? pchNewLine - pszLeft + 1 : cchLeft;
     469                                        if (g_cchBuf + cchLine <= sizeof(g_achBuf)) {
     470                                                memcpy(&g_achBuf[g_cchBuf], pszLeft, cchLine);
     471                                                g_cchBuf += cchLine;
     472                                        } else {
     473                                                if (flush_buffer() < 0) {
     474                                                        return -1;
     475                                                }
     476                                                if (fwrite(pszLeft, cchLine, 1, stdout) < 1) {
     477                                                        return -1;
     478                                                }
     479                                        }
     480                                        pszLeft += cchLine;
     481                                        cchLeft -= cchLine;
     482                                }
     483                        }
     484                }
     485                free(pszTmp);
     486        }
     487        return (int)cchRet;
     488}
     489
     490/**
     491 * Flushes the g_abBuf/g_cchBuf.
     492 */
     493static int flush_buffer(void)
     494{
     495    if (g_cchBuf > 0) {
     496                ssize_t cchToWrite = g_cchBuf;
     497                ssize_t cchWritten = fwrite(g_achBuf, 1, g_cchBuf, stdout);
     498                g_cchBuf = 0;
     499                if (cchWritten >= cchToWrite) {
     500                        /* likely */
     501                } else {
     502                        ssize_t off = cchWritten;
     503                        if (cchWritten >= 0) {
     504                                off = cchWritten;
     505                        } else if (errno == EINTR) {
     506                                cchWritten = 0;
     507                        } else {
     508                                return -1;
     509                        }
     510
     511                        while (off < cchToWrite) {
     512                                cchWritten = fwrite(&g_achBuf[off], 1, cchToWrite - off, stdout);
     513                                if (cchWritten > 0) {
     514                                        off += cchWritten;
     515                                } else if (errno == EINTR) {
     516                                        /* nothing */
     517                                } else {
     518                                        return -1;
     519                                }
     520                        }
     521                }
     522    }
     523    return 0;
     524}
     525
    438526
    439527
  • trunk/src/kmk/main.c

    r2818 r2900  
    13801380  char *windows32_path = NULL;
    13811381
    1382 #ifndef ELECTRIC_HEAP /* Drop this because it prevents JIT debugging. */
     1382# ifndef ELECTRIC_HEAP /* Drop this because it prevents JIT debugging. */
    13831383  SetUnhandledExceptionFilter(handle_runtime_exceptions);
    1384 #endif /* !ELECTRIC_HEAP */
     1384# endif /* !ELECTRIC_HEAP */
    13851385
    13861386  /* start off assuming we have no shell */
  • trunk/src/lib/Makefile.kmk

    r2886 r2900  
    3939        crc32.c \
    4040        md5.c \
     41        maybe_con_write.c \
     42        maybe_con_fwrite.c \
    4143        kbuild_version.c
    4244kUtil_SOURCES.win = \
  • trunk/src/lib/nt/ntstuff.h

    r2862 r2900  
    7474} MY_STRING;
    7575typedef MY_STRING MY_ANSI_STRING;
     76
     77typedef struct MY_CURDIR
     78{
     79    UNICODE_STRING      DosPath;
     80    HANDLE              Handle;
     81} MY_CURDIR;
     82typedef MY_CURDIR *PMY_CURDIR;
     83
     84typedef struct MY_RTL_DRIVE_LETTER_CURDIR
     85{
     86    USHORT              Flags;
     87    USHORT              Length;
     88    ULONG               TimeStamp;
     89    MY_ANSI_STRING      DosPath;
     90} MY_RTL_DRIVE_LETTER_CURDIR;
     91typedef MY_RTL_DRIVE_LETTER_CURDIR *PRTL_DRIVE_LETTER_CURDIR;
     92
     93typedef struct MY_RTL_USER_PROCESS_PARAMETERS
     94{
     95    ULONG               MaximumLength;
     96    ULONG               Length;
     97    ULONG               Flags;
     98    ULONG               DebugFlags;
     99    HANDLE              ConsoleHandle;
     100    ULONG               ConsoleFlags;
     101    HANDLE              StandardInput;
     102    HANDLE              StandardOutput;
     103    HANDLE              StandardError;
     104    MY_CURDIR           CurrentDirectory;
     105    MY_UNICODE_STRING   DllPath;
     106    MY_UNICODE_STRING   ImagePathName;
     107    MY_UNICODE_STRING   CommandLine;
     108    PWSTR               Environment;
     109    ULONG               StartingX;
     110    ULONG               StartingY;
     111    ULONG               CountX;
     112    ULONG               CountY;
     113    ULONG               CountCharsX;
     114    ULONG               CountCharsY;
     115    ULONG               FillAttribute;
     116    ULONG               WindowFlags;
     117    ULONG               ShowWindowFlags;
     118    MY_UNICODE_STRING   WindowTitle;
     119    MY_UNICODE_STRING   DesktopInfo;
     120    MY_UNICODE_STRING   ShellInfo;
     121    MY_UNICODE_STRING   RuntimeInfo;
     122    MY_RTL_DRIVE_LETTER_CURDIR CurrentDirectories[0x20];
     123    SIZE_T              EnvironmentSize;        /* >= Vista+ */
     124    SIZE_T              EnvironmentVersion;     /* >= Windows 7. */
     125    PVOID               PackageDependencyData;  /* >= Windows 8 or Windows 8.1. */
     126    ULONG               ProcessGroupId;         /* >= Windows 8 or Windows 8.1. */
     127} MY_RTL_USER_PROCESS_PARAMETERS;
     128typedef MY_RTL_USER_PROCESS_PARAMETERS *PMY_RTL_USER_PROCESS_PARAMETERS;
    76129
    77130typedef struct MY_OBJECT_ATTRIBUTES
Note: See TracChangeset for help on using the changeset viewer.

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