* switch output and error stream to non blocking and snooze between each run.

* read error messages and present an alert with the option to stop processing
* should fix #1870 and help with #5009


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@38871 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Jérôme Duval 2010-10-03 11:52:35 +00:00
parent 97176323ed
commit 750111c966
3 changed files with 64 additions and 53 deletions

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2004-2006, Jérôme Duval. All rights reserved. * Copyright 2004-2010, Jérôme Duval. All rights reserved.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
* Original code from ZipOMatic by jonas.sundstrom@kirilla.com * Original code from ZipOMatic by jonas.sundstrom@kirilla.com
*/ */
@ -21,8 +21,7 @@ ExpanderThread::ExpanderThread(BMessage * refs_message, BMessenger * messenger)
fStdOut(-1), fStdOut(-1),
fStdErr(-1), fStdErr(-1),
fExpanderOutput(NULL), fExpanderOutput(NULL),
fExpanderOutputString(), fExpanderError(NULL)
fExpanderOutputBuffer(new char [4096])
{ {
SetDataStore(new BMessage(* refs_message)); // leak? SetDataStore(new BMessage(* refs_message)); // leak?
// prevents bug with B_SIMPLE_DATA // prevents bug with B_SIMPLE_DATA
@ -33,16 +32,15 @@ ExpanderThread::ExpanderThread(BMessage * refs_message, BMessenger * messenger)
ExpanderThread::~ExpanderThread() ExpanderThread::~ExpanderThread()
{ {
delete fWindowMessenger; delete fWindowMessenger;
delete [] fExpanderOutputBuffer;
} }
status_t status_t
ExpanderThread::ThreadStartup() ExpanderThread::ThreadStartup()
{ {
status_t status = B_OK; status_t status = B_OK;
entry_ref srcRef, destRef; entry_ref srcRef, destRef;
BString cmd; BString cmd;
if ((status = GetDataStore()->FindRef("srcRef", &srcRef)) != B_OK) if ((status = GetDataStore()->FindRef("srcRef", &srcRef)) != B_OK)
return status; return status;
@ -63,9 +61,9 @@ ExpanderThread::ThreadStartup()
int32 argc = 3; int32 argc = 3;
const char ** argv = new const char * [argc + 1]; const char ** argv = new const char * [argc + 1];
argv[0] = strdup("/bin/sh"); argv[0] = strdup("/bin/sh");
argv[1] = strdup("-c"); argv[1] = strdup("-c");
argv[2] = strdup(cmd.String()); argv[2] = strdup(cmd.String());
argv[argc] = NULL; argv[argc] = NULL;
fThreadId = PipeCommand(argc, argv, fStdIn, fStdOut, fStdErr); fThreadId = PipeCommand(argc, argv, fStdIn, fStdOut, fStdErr);
@ -79,9 +77,17 @@ ExpanderThread::ThreadStartup()
set_thread_priority(fThreadId, B_LOW_PRIORITY); set_thread_priority(fThreadId, B_LOW_PRIORITY);
resume_thread(fThreadId); resume_thread(fThreadId);
int flags = fcntl(fStdOut, F_GETFL, 0);
flags |= O_NONBLOCK;
fcntl(fStdOut, F_SETFL, flags);
flags = fcntl(fStdErr, F_GETFL, 0);
flags |= O_NONBLOCK;
fcntl(fStdErr, F_SETFL, flags);
fExpanderOutput = fdopen(fStdOut, "r"); fExpanderOutput = fdopen(fStdOut, "r");
fExpanderError = fdopen(fStdErr, "r");
return B_OK; return B_OK;
} }
@ -89,23 +95,33 @@ ExpanderThread::ThreadStartup()
status_t status_t
ExpanderThread::ExecuteUnit(void) ExpanderThread::ExecuteUnit(void)
{ {
// read output from command // read output and error from command
// send it to window // send it to window
char *output_string = fgets(fExpanderOutputBuffer , 4096 - 1, fExpanderOutput);
if (output_string == NULL)
return EOF;
BMessage message('outp'); BMessage message('outp');
message.AddString("output", output_string); bool outputAdded = false;
for (int32 i = 0; i < 5; i++) { for (int32 i = 0; i < 50; i++) {
output_string = fgets(fExpanderOutputBuffer , 4096 - 1, fExpanderOutput); char *output_string = fgets(fExpanderOutputBuffer , LINE_MAX, fExpanderOutput);
if (!output_string) if (!output_string)
break; break;
message.AddString("output", output_string); message.AddString("output", output_string);
outputAdded = true;
} }
fWindowMessenger->SendMessage(&message); if (outputAdded)
fWindowMessenger->SendMessage(&message);
if (feof(fExpanderOutput))
return EOF;
char *error_string = fgets(fExpanderOutputBuffer , LINE_MAX, fExpanderError);
if (error_string != NULL
&& strcmp(error_string, "\n")) {
BMessage message('errp');
message.AddString("error", error_string);
fWindowMessenger->SendMessage(&message);
}
// streams are non blocking, sleep every 100ms
snooze(100000);
return B_OK; return B_OK;
} }
@ -173,7 +189,7 @@ ExpanderThread::PipeCommand(int argc, const char **argv, int &in, int &out, int
int old_err = dup(2); int old_err = dup(2);
int filedes[2]; int filedes[2];
/* Create new pipe FDs as stdin, stdout, stderr */ /* Create new pipe FDs as stdin, stdout, stderr */
pipe(filedes); dup2(filedes[0], 0); close(filedes[0]); pipe(filedes); dup2(filedes[0], 0); close(filedes[0]);
in = filedes[1]; // Write to in, appears on cmd's stdin in = filedes[1]; // Write to in, appears on cmd's stdin

View File

@ -1,30 +1,8 @@
/*****************************************************************************/ /*
// Expander * Copyright 2004-2010, Jérôme Duval. All rights reserved.
// Written by Jérôme Duval * Distributed under the terms of the MIT License.
// * Original code from ZipOMatic by jonas.sundstrom@kirilla.com
// ExpanderThread.h */
//
// Copyright (c) 2004 OpenBeOS Project
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
/*****************************************************************************/
#ifndef __EXPANDERTHREAD_H__ #ifndef __EXPANDERTHREAD_H__
#define __EXPANDERTHREAD_H__ #define __EXPANDERTHREAD_H__
@ -74,8 +52,8 @@ class ExpanderThread : public GenericThread
int fStdOut; int fStdOut;
int fStdErr; int fStdErr;
FILE * fExpanderOutput; FILE * fExpanderOutput;
BString fExpanderOutputString; FILE * fExpanderError;
char * fExpanderOutputBuffer; char fExpanderOutputBuffer[LINE_MAX];
}; };
#endif // __EXPANDERTHREAD_H__ #endif // __EXPANDERTHREAD_H__

View File

@ -337,7 +337,24 @@ ExpanderWindow::MessageReceived(BMessage* msg)
fListingText->ScrollToSelection(); fListingText->ScrollToSelection();
} }
break; break;
case 'errp':
{
BString string;
if (msg->FindString("error", &string) == B_OK
&& fExpandingStarted) {
fExpandingThread->SuspendExternalExpander();
BAlert* alert = new BAlert("stopAlert", string,
B_TRANSLATE("Stop"), B_TRANSLATE("Continue"), NULL,
B_WIDTH_AS_USUAL, B_EVEN_SPACING, B_WARNING_ALERT);
if (alert->Go() == 0) {
fExpandingThread->ResumeExternalExpander();
StopExpanding();
} else
fExpandingThread->ResumeExternalExpander();
}
break;
}
case 'exit': case 'exit':
// thread has finished (finished, quit, killed, we don't know) // thread has finished (finished, quit, killed, we don't know)
// reset window state // reset window state