* 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.
* Original code from ZipOMatic by jonas.sundstrom@kirilla.com
*/
@ -21,8 +21,7 @@ ExpanderThread::ExpanderThread(BMessage * refs_message, BMessenger * messenger)
fStdOut(-1),
fStdErr(-1),
fExpanderOutput(NULL),
fExpanderOutputString(),
fExpanderOutputBuffer(new char [4096])
fExpanderError(NULL)
{
SetDataStore(new BMessage(* refs_message)); // leak?
// prevents bug with B_SIMPLE_DATA
@ -33,16 +32,15 @@ ExpanderThread::ExpanderThread(BMessage * refs_message, BMessenger * messenger)
ExpanderThread::~ExpanderThread()
{
delete fWindowMessenger;
delete [] fExpanderOutputBuffer;
}
status_t
ExpanderThread::ThreadStartup()
{
status_t status = B_OK;
entry_ref srcRef, destRef;
BString cmd;
status_t status = B_OK;
entry_ref srcRef, destRef;
BString cmd;
if ((status = GetDataStore()->FindRef("srcRef", &srcRef)) != B_OK)
return status;
@ -63,9 +61,9 @@ ExpanderThread::ThreadStartup()
int32 argc = 3;
const char ** argv = new const char * [argc + 1];
argv[0] = strdup("/bin/sh");
argv[1] = strdup("-c");
argv[2] = strdup(cmd.String());
argv[0] = strdup("/bin/sh");
argv[1] = strdup("-c");
argv[2] = strdup(cmd.String());
argv[argc] = NULL;
fThreadId = PipeCommand(argc, argv, fStdIn, fStdOut, fStdErr);
@ -79,9 +77,17 @@ ExpanderThread::ThreadStartup()
set_thread_priority(fThreadId, B_LOW_PRIORITY);
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");
fExpanderError = fdopen(fStdErr, "r");
return B_OK;
}
@ -89,23 +95,33 @@ ExpanderThread::ThreadStartup()
status_t
ExpanderThread::ExecuteUnit(void)
{
// read output from command
// read output and error from command
// send it to window
char *output_string = fgets(fExpanderOutputBuffer , 4096 - 1, fExpanderOutput);
if (output_string == NULL)
return EOF;
BMessage message('outp');
message.AddString("output", output_string);
for (int32 i = 0; i < 5; i++) {
output_string = fgets(fExpanderOutputBuffer , 4096 - 1, fExpanderOutput);
bool outputAdded = false;
for (int32 i = 0; i < 50; i++) {
char *output_string = fgets(fExpanderOutputBuffer , LINE_MAX, fExpanderOutput);
if (!output_string)
break;
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;
}
@ -173,7 +189,7 @@ ExpanderThread::PipeCommand(int argc, const char **argv, int &in, int &out, int
int old_err = dup(2);
int filedes[2];
/* Create new pipe FDs as stdin, stdout, stderr */
pipe(filedes); dup2(filedes[0], 0); close(filedes[0]);
in = filedes[1]; // Write to in, appears on cmd's stdin

View File

@ -1,30 +1,8 @@
/*****************************************************************************/
// Expander
// Written by Jérôme Duval
//
// 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.
/*****************************************************************************/
/*
* Copyright 2004-2010, Jérôme Duval. All rights reserved.
* Distributed under the terms of the MIT License.
* Original code from ZipOMatic by jonas.sundstrom@kirilla.com
*/
#ifndef __EXPANDERTHREAD_H__
#define __EXPANDERTHREAD_H__
@ -74,8 +52,8 @@ class ExpanderThread : public GenericThread
int fStdOut;
int fStdErr;
FILE * fExpanderOutput;
BString fExpanderOutputString;
char * fExpanderOutputBuffer;
FILE * fExpanderError;
char fExpanderOutputBuffer[LINE_MAX];
};
#endif // __EXPANDERTHREAD_H__

View File

@ -337,7 +337,24 @@ ExpanderWindow::MessageReceived(BMessage* msg)
fListingText->ScrollToSelection();
}
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':
// thread has finished (finished, quit, killed, we don't know)
// reset window state