[gparted/psusi/refactor: 3/19] Add async version of FileSystem::execute_command()
- From: Phillip Susi <psusi src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gparted/psusi/refactor: 3/19] Add async version of FileSystem::execute_command()
- Date: Tue, 20 Mar 2012 00:02:41 +0000 (UTC)
commit ca74ac5f7627876922021cbddc35d16b0fc51f1f
Author: Phillip Susi <psusi ubuntu com>
Date: Sun Feb 12 19:03:30 2012 -0500
Add async version of FileSystem::execute_command()
The new function allows the filesystems to execute their external commands
asynchronously. The stdout and stderr of the child process are connected
to pipes that are monitored by a new class PipeCapture, which gets notified
when the pipes are readable and reads them into the output and error
ustrings similar to the old execute_command(). Once the pipes have reached
eof, and the child process has exited, a callback is invoked to indicate
completion. The callback is passed a value between 0.0 and 1.0 to indicate
how much progress has been made, and returns true if cancellation is
requested. For now, only a value of 1.0 is used and the return value is
ignored.
The old execute_command has been implemented using the new async version
and then blocking the thread on a mutex until completion.
include/FileSystem.h | 53 ++++++++++++-
src/FileSystem.cc | 201 +++++++++++++++++++++++++++++++++++++++++++++++--
2 files changed, 241 insertions(+), 13 deletions(-)
---
diff --git a/include/FileSystem.h b/include/FileSystem.h
index 2202402..400a2ee 100644
--- a/include/FileSystem.h
+++ b/include/FileSystem.h
@@ -28,36 +28,74 @@
namespace GParted
{
+// captures output pipe of subprocess into a ustring and emits a progress signal
+// with the value 1.0 when eof is reached
+
+class PipeCapture
+{
+ Glib::ustring &buff;
+ Glib::RefPtr<Glib::IOChannel> channel;
+ sigc::connection connection;
+ bool OnReadable( Glib::IOCondition condition );
+ sigc::slot<bool, double> progressslot;
+public:
+ PipeCapture( int fd, Glib::ustring &buffer, sigc::slot<bool, double> slot );
+ ~PipeCapture();
+};
+
class FileSystem
{
public:
FileSystem() ;
- virtual ~FileSystem() {}
+ virtual ~FileSystem();
virtual const Glib::ustring get_custom_text( CUSTOM_TEXT ttype, int index = 0 ) ;
static const Glib::ustring get_generic_text( CUSTOM_TEXT ttype, int index = 0 ) ;
virtual FS get_filesystem_support() = 0 ;
virtual void set_used_sectors( Partition & partition ) = 0 ;
+ virtual void set_used_sectors( Partition & partition, sigc::slot<bool, double> slot );
virtual void read_label( Partition & partition ) = 0 ;
+ virtual void read_label( Partition & partition, sigc::slot<bool, double> slot );
virtual bool write_label( const Partition & partition, OperationDetail & operationdetail ) = 0 ;
+ virtual void write_label( const Partition & partition, OperationDetail & operationdetail,
+ sigc::slot<bool, double> slot );
virtual void read_uuid( Partition & partition ) = 0 ;
+ virtual void read_uuid( Partition & partition, sigc::slot<bool, double> slot );
virtual bool write_uuid( const Partition & partition, OperationDetail & operationdetail ) = 0 ;
+ virtual void write_uuid( const Partition & partition, OperationDetail & operationdetail,
+ sigc::slot<bool, double> slot );
virtual bool create( const Partition & new_partition, OperationDetail & operationdetail ) = 0 ;
+ virtual void create( const Partition & new_partition, OperationDetail & operationdetail,
+ sigc::slot<bool, double> slot );
virtual bool resize( const Partition & partition_new,
OperationDetail & operationdetail,
bool fill_partition = false ) = 0 ;
+ virtual void resize( const Partition & partition_new, OperationDetail & operationdetail,
+ bool fill_partition, sigc::slot<bool, double> slot );
virtual bool move( const Partition & partition_new
, const Partition & partition_old
, OperationDetail & operationdetail
) = 0 ;
+ virtual void move( const Partition & partition_new, const Partition & partition_old,
+ OperationDetail & operationdetail, sigc::slot<bool, double> slot );
virtual bool copy( const Glib::ustring & src_part_path,
const Glib::ustring & dest_part_path,
OperationDetail & operationdetail ) = 0 ;
+ virtual void copy( const Glib::ustring & src_part_path, const Glib::ustring & dest_part_path,
+ OperationDetail & operationdetail, sigc::slot<bool, double> slot );
virtual bool check_repair( const Partition & partition, OperationDetail & operationdetail ) = 0 ;
-
+ virtual void check_repair( const Partition & partition, OperationDetail & operationdetail,
+ sigc::slot<bool, double> slot );
+ sigc::slot<bool, double> unlock_mutex;
+ sigc::slot<bool, double> set_success;
+ Glib::Mutex mutex;
+ bool success;
protected:
int execute_command( const Glib::ustring & command, OperationDetail & operationdetail ) ;
+ void execute_command( const Glib::ustring & command, OperationDetail & operationdetail, sigc::slot<bool, double> progresscb );
+ void execute_command( const Glib::ustring & command, sigc::slot<bool, double> progresscb );
+ bool execute_command_progress( double progress );
int execute_command_timed( const Glib::ustring & command
, OperationDetail & operationdetail
, bool check_status = true ) ;
@@ -66,12 +104,19 @@ protected:
//those are used in several places..
Glib::ustring output, error ;
+ PipeCapture *outputcapture, *errorcapture;
+ sigc::slot<bool, double> slot;
Sector N, S ;
int exit_status ;
unsigned int index ;
-
private:
-
+ bool unlock_mutex_f( double progress );
+ bool set_success_f( double progress );
+ OperationDetail *cmdoperationdetail;
+ int pipecount;
+ sigc::slot<bool, double> progressslot;
+ void store_exit_status( GPid pid, int status );
+ bool running;
};
} //GParted
diff --git a/src/FileSystem.cc b/src/FileSystem.cc
index 8b02404..8f455e7 100644
--- a/src/FileSystem.cc
+++ b/src/FileSystem.cc
@@ -19,12 +19,72 @@
#include "../include/FileSystem.h"
#include <cerrno>
+#include <iostream>
namespace GParted
{
-
+
+PipeCapture::PipeCapture( int fd, Glib::ustring &string, sigc::slot<bool, double> slot ) : buff( string ), progressslot( slot )
+{
+ // tie fd to string
+ // make channel
+ channel = Glib::IOChannel::create_from_fd( fd );
+ connection = Glib::signal_io().connect(
+ sigc::mem_fun( *this, &PipeCapture::OnReadable ),
+ fd,
+ Glib::IO_IN | Glib::IO_HUP | Glib::IO_ERR );
+}
+
+bool PipeCapture::OnReadable( Glib::IOCondition condition )
+{
+ // read from pipe and store in buff
+ Glib::ustring str;
+ Glib::IOStatus status = channel->read( str, 512 );
+ if (status == Glib::IO_STATUS_NORMAL)
+ {
+ buff += str;
+ return true;
+ }
+ if (status != Glib::IO_STATUS_EOF)
+ std::cerr << "Pipe IOChannel read failed" << std::endl;
+ // signal completion
+ progressslot( 1.0 );
+ return false;
+}
+
+PipeCapture::~PipeCapture()
+{
+ connection.disconnect();
+}
+
FileSystem::FileSystem()
{
+ unlock_mutex = sigc::mem_fun( *this, &FileSystem::unlock_mutex_f );
+ set_success = sigc::mem_fun( *this, &FileSystem::set_success_f );
+ mutex.lock(); // set initial state to locked
+}
+
+FileSystem::~FileSystem()
+{
+ mutex.unlock();
+}
+
+bool FileSystem::unlock_mutex_f( double progress )
+{
+ if( progress == 1.0 )
+ {
+ mutex.unlock();
+ }
+ return false;
+}
+
+bool FileSystem::set_success_f( double progress )
+{
+ if ( progress == 1.0 )
+ {
+ success = !exit_status;
+ return slot( 1.0 );
+ } else return false;
}
const Glib::ustring FileSystem::get_custom_text( CUSTOM_TEXT ttype, int index )
@@ -50,17 +110,73 @@ const Glib::ustring FileSystem::get_generic_text( CUSTOM_TEXT ttype, int index )
int FileSystem::execute_command( const Glib::ustring & command, OperationDetail & operationdetail )
{
- operationdetail .add_child( OperationDetail( command, STATUS_NONE, FONT_BOLD_ITALIC ) ) ;
+ execute_command( command, operationdetail, unlock_mutex );
+ mutex.lock(); // wait for completion
+ return exit_status ;
+}
- int exit_status = Utils::execute_command( "nice -n 19 " + command, output, error ) ;
+void FileSystem::store_exit_status( GPid pid, int status )
+{
+ exit_status = status;
+ running = false;
+ if (pipecount == 0) // pipes finished first
+ progressslot( 1.0 );
+ Glib::spawn_close_pid( pid );
+}
- if ( ! output .empty() )
- operationdetail .get_last_child() .add_child( OperationDetail( output, STATUS_NONE, FONT_ITALIC ) ) ;
-
- if ( ! error .empty() )
- operationdetail .get_last_child() .add_child( OperationDetail( error, STATUS_NONE, FONT_ITALIC ) ) ;
+void FileSystem::execute_command( const Glib::ustring & command, sigc::slot<bool, double> progresscb )
+{
+ Glib::Pid pid;
+ // set up pipes for capture
+ int out, err;
+ // spawn external process
+ cmdoperationdetail = 0;
+ Glib::spawn_async_with_pipes(
+ std::string(),
+ Glib::shell_parse_argv( command ),
+ Glib::SPAWN_DO_NOT_REAP_CHILD | Glib::SPAWN_SEARCH_PATH,
+ sigc::slot< void >(),
+ &pid,
+ 0,
+ &out,
+ &err );
+ running = true;
+ progressslot = progresscb;
+ Glib::signal_child_watch().connect( sigc::mem_fun( *this, &FileSystem::store_exit_status ), pid );
+ output.clear();
+ error.clear();
+ outputcapture = new PipeCapture( out, output, sigc::mem_fun( *this, &FileSystem::execute_command_progress) );
+ errorcapture = new PipeCapture( err, error, sigc::mem_fun( *this, &FileSystem::execute_command_progress) );
+ pipecount = 2;
+}
- return exit_status ;
+void FileSystem::execute_command( const Glib::ustring & command, OperationDetail & operationdetail, sigc::slot<bool, double> progresscb )
+{
+ operationdetail .add_child( OperationDetail( command, STATUS_EXECUTE, FONT_BOLD_ITALIC ) ) ;
+ execute_command( command, progresscb );
+ cmdoperationdetail = &operationdetail;
+}
+
+bool FileSystem::execute_command_progress( double progress )
+{
+ if (progress < 1.0)
+ progressslot( progress );
+ // propogate up progress, clean up on completion
+ if (--pipecount)
+ return false; // wait for second pipe to eof
+ delete outputcapture;
+ delete errorcapture;
+ if ( cmdoperationdetail )
+ {
+ if ( !output.empty() )
+ cmdoperationdetail->get_last_child().add_child( OperationDetail( output, STATUS_NONE, FONT_ITALIC ) );
+
+ if ( !error.empty() )
+ cmdoperationdetail->get_last_child().add_child( OperationDetail( error, STATUS_NONE, FONT_ITALIC ) );
+ }
+ if ( !running ) // already got exit status
+ progressslot( progress );
+ return false;
}
//Time command, add results to operation detail and by default set success or failure
@@ -152,4 +268,71 @@ void FileSystem::rm_temp_dir( const Glib::ustring dir_name, OperationDetail & op
}
}
+void FileSystem::set_used_sectors( Partition & partition, sigc::slot<bool, double> slot )
+{
+ success = false;
+ slot( 1.0 );
+}
+
+void FileSystem::read_label( Partition & partition, sigc::slot<bool, double> slot )
+{
+ success = false;
+ slot( 1.0 );
+}
+
+void FileSystem::write_label( const Partition & partition, OperationDetail & operationdetail,
+ sigc::slot<bool, double> slot )
+{
+ success = false;
+ slot( 1.0 );
+}
+
+void FileSystem::read_uuid( Partition & partition, sigc::slot<bool, double> slot )
+{
+ success = false;
+ slot( 1.0 );
+}
+
+void FileSystem::write_uuid( const Partition & partition, OperationDetail & operationdetail,
+ sigc::slot<bool, double> slot )
+{
+ success = false;
+ slot( 1.0 );
+}
+
+void FileSystem::create( const Partition & new_partition, OperationDetail & operationdetail,
+ sigc::slot<bool, double> slot )
+{
+ success = false;
+ slot( 1.0 );
+}
+
+void FileSystem::resize( const Partition & partition_new, OperationDetail & operationdetail,
+ bool fill_partition, sigc::slot<bool, double> slot )
+{
+ success = false;
+ slot( 1.0 );
+}
+
+void FileSystem::move( const Partition & partition_new, const Partition & partition_old,
+ OperationDetail & operationdetail, sigc::slot<bool, double> slot )
+{
+ success = false;
+ slot( 1.0 );
+}
+
+void FileSystem::copy( const Glib::ustring & src_part_path, const Glib::ustring & dest_part_path,
+ OperationDetail & operationdetail, sigc::slot<bool, double> slot )
+{
+ success = false;
+ slot( 1.0 );
+}
+
+void FileSystem::check_repair( const Partition & partition, OperationDetail & operationdetail,
+ sigc::slot<bool, double> slot )
+{
+ success = false;
+ slot( 1.0 );
+}
+
} //GParted
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]