VirtualBox

Ignore:
Timestamp:
Apr 30, 2010 10:21:00 AM (15 years ago)
Author:
vboxsync
Message:

Guest Control/VBoxManage,Main: Immediate process output, now also cancelable with signal handling.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrl.cpp

    r28920 r28926  
    4444#endif
    4545
     46#include <signal.h>
     47
    4648#ifdef RT_OS_DARWIN
    4749# include <CoreFoundation/CFRunLoop.h>
     
    5557 */
    5658/** @todo */
     59
     60/** Set by the signal handler. */
     61static volatile bool    g_fExecCanceled = false;
    5762
    5863void usageGuestControl(void)
     
    6570             "                            [--verbose] [--wait-for exit,stdout,stderr||]\n"
    6671             "\n");
     72}
     73
     74/**
     75 * Signal handler that sets g_fCanceled.
     76 *
     77 * This can be executed on any thread in the process, on Windows it may even be
     78 * a thread dedicated to delivering this signal.  Do not doing anything
     79 * unnecessary here.
     80 */
     81static void execProcessSignalHandler(int iSignal)
     82{
     83    NOREF(iSignal);
     84    ASMAtomicWriteBool(&g_fExecCanceled, true);
    6785}
    6886
     
    305323                    RTPrintf("Waiting for process to exit ...\n");                       
    306324
     325                /* setup signal handling if cancelable */
     326                ASSERT(progress);
     327                bool fCanceledAlready = false;
     328                BOOL fCancelable;
     329                HRESULT hrc = progress->COMGETTER(Cancelable)(&fCancelable);
     330                if (FAILED(hrc))
     331                    fCancelable = FALSE;
     332                if (fCancelable)
     333                {
     334                    signal(SIGINT,   execProcessSignalHandler);
     335            #ifdef SIGBREAK
     336                    signal(SIGBREAK, execProcessSignalHandler);
     337            #endif
     338                }
     339
    307340                /* Wait for process to exit ... */
    308                 ASSERT(progress);
    309                 rc = progress->WaitForCompletion(have_timeout ?
    310                                                  (u32TimeoutMS + 5000) :    /* Timeout value + safety counter */
    311                                                   -1                        /* Wait forever */);
    312                 if (FAILED(rc))
    313                 {
    314                     if (u32TimeoutMS)
    315                         RTPrintf("Process '%s' (PID: %u) did not end within %ums! Wait aborted.\n",
    316                                  Utf8Cmd.raw(), uPID, u32TimeoutMS);
    317                     break;
    318                 }
    319                 else
    320                 {
    321                     BOOL completed;
    322                     CHECK_ERROR_RET(progress, COMGETTER(Completed)(&completed), rc);
    323                     ASSERT(completed);
    324 
    325                     LONG iRc;
     341                BOOL fCompleted = false;
     342                ULONG cbOutputData = 0;
     343                SafeArray<BYTE> aOutputData;
     344                while (SUCCEEDED(progress->COMGETTER(Completed(&fCompleted))))
     345                {
     346                    if (cbOutputData <= 0)
     347                    {
     348                        if (fCompleted)
     349                            break;
     350
     351                        if (   have_timeout
     352                            && RTTimeMilliTS() - u64StartMS > u32TimeoutMS + 5000)
     353                        {
     354                            progress->Cancel();
     355                            break;
     356                        }
     357                    }
     358
     359                    CHECK_ERROR_BREAK(guest, GetProcessOutput(uPID, 0 /* aFlags */,
     360                                                              u32TimeoutMS, _64K, ComSafeArrayAsOutParam(aOutputData)));
     361                    cbOutputData = aOutputData.size();
     362                    if (cbOutputData > 0)
     363                    {
     364                        /* aOutputData has a platform dependent line ending, standardize on
     365                         * Unix style, as RTStrmWrite does the LF -> CR/LF replacement on
     366                         * Windows. Otherwise we end up with CR/CR/LF on Windows. */
     367                        ULONG cbOutputDataPrint = cbOutputData;
     368                        for (BYTE *s = aOutputData.raw(), *d = s;
     369                             s - aOutputData.raw() < (ssize_t)cbOutputData;
     370                             s++, d++)
     371                        {
     372                            if (*s == '\r')
     373                            {
     374                                /* skip over CR, adjust destination */
     375                                d--;
     376                                cbOutputDataPrint--;
     377                            }
     378                            else if (s != d)
     379                                *d = *s;
     380                        }
     381                        RTStrmWrite(g_pStdOut, aOutputData.raw(), cbOutputDataPrint);
     382                    }
     383
     384                    /* process async cancelation. */
     385                    if (g_fExecCanceled && !fCanceledAlready)
     386                    {
     387                        hrc = progress->Cancel();
     388                        if (SUCCEEDED(hrc))
     389                            fCanceledAlready = true;
     390                        else
     391                            g_fExecCanceled = false;
     392                    }
     393
     394                    progress->WaitForCompletion(100);
     395                }
     396
     397                /* undo signal handling */
     398                if (fCancelable)
     399                {
     400                    signal(SIGINT,   SIG_DFL);
     401            #ifdef SIGBREAK
     402                    signal(SIGBREAK, SIG_DFL);
     403            #endif
     404                }
     405
     406                /* Not completed yet? -> Timeout */
     407                if (fCompleted)
     408                {
     409                    LONG iRc = false;
    326410                    CHECK_ERROR_RET(progress, COMGETTER(ResultCode)(&iRc), rc);
    327411                    if (FAILED(iRc))
     
    330414                        rc = progress->COMGETTER(ErrorInfo)(execError.asOutParam());
    331415                        com::ErrorInfo info (execError);
    332                         RTPrintf("Process error details:\n");
     416                        RTPrintf("\n\nProcess error details:\n");
    333417                        GluePrintErrorInfo(info);
    334418                        RTPrintf("\n");
    335                     }
    336 
     419                    }         
     420                }
     421                else
     422                {
     423                    RTPrintf("Process timed out!\n");
     424                }
     425               
     426                if (verbose)
     427                {
    337428                    ULONG uRetStatus, uRetExitCode, uRetFlags;
    338429                    CHECK_ERROR_BREAK(guest, GetProcessStatus(uPID, &uRetExitCode, &uRetFlags, &uRetStatus));
    339                     if (verbose)
    340                         RTPrintf("Exit code=%u (Status=%u, Flags=%u)\n", uRetExitCode, uRetStatus, uRetFlags);
    341 
    342                     /* Print output if wanted. */
    343                     if (   waitForStdOut
    344                         || waitForStdErr)
    345                     {
    346                         bool bFound = false;
    347                         while (true)
    348                         {
    349                             SafeArray<BYTE> aOutputData;
    350                             ULONG cbOutputData;
    351                             CHECK_ERROR_BREAK(guest, GetProcessOutput(uPID, 0 /* aFlags */,
    352                                                                       u32TimeoutMS, _64K, ComSafeArrayAsOutParam(aOutputData)));
    353                             cbOutputData = aOutputData.size();
    354                             if (cbOutputData == 0)
    355                                 break;
    356 
    357                             if (!bFound && verbose)
    358                             {
    359                                 RTPrintf("Retrieving output data ...\n");
    360                                 bFound = true;
    361                             }
    362 
    363                             /* aOutputData has a platform dependent line ending, standardize on
    364                              * Unix style, as RTStrmWrite does the LF -> CR/LF replacement on
    365                              * Windows. Otherwise we end up with CR/CR/LF on Windows. */
    366                             ULONG cbOutputDataPrint = cbOutputData;
    367                             for (BYTE *s = aOutputData.raw(), *d = s;
    368                                  s - aOutputData.raw() < (ssize_t)cbOutputData;
    369                                  s++, d++)
    370                             {
    371                                 if (*s == '\r')
    372                                 {
    373                                     /* skip over CR, adjust destination */
    374                                     d--;
    375                                     cbOutputDataPrint--;
    376                                 }
    377                                 else if (s != d)
    378                                     *d = *s;
    379                             }
    380                             RTStrmWrite(g_pStdOut, aOutputData.raw(), cbOutputDataPrint);
    381                         }
    382                         if (!bFound && verbose)
    383                             RTPrintf("No output data available\n");
    384                     }
     430                    RTPrintf("Exit code=%u (Status=%u, Flags=%u)\n", uRetExitCode, uRetStatus, uRetFlags);
    385431                }
    386432            }
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