2007-09-28 Marcus Brinkmann <marcus@g10code.de>

* kdpipeiodevice.moc, w32-qt-io.cpp, kdpipeiodevice.cpp: New
	versions from Frank Osterfeld.
This commit is contained in:
Marcus Brinkmann 2007-09-27 22:21:10 +00:00
parent 37ac53e74c
commit 7e82572bb2
4 changed files with 239 additions and 110 deletions

View File

@ -1,3 +1,8 @@
2007-09-28 Marcus Brinkmann <marcus@g10code.de>
* kdpipeiodevice.moc, w32-qt-io.cpp, kdpipeiodevice.cpp: New
versions from Frank Osterfeld.
2007-09-27 Marcus Brinkmann <marcus@g10code.de> 2007-09-27 Marcus Brinkmann <marcus@g10code.de>
* w32-glib-io.c (_gpgme_io_spawn), * w32-glib-io.c (_gpgme_io_spawn),

View File

@ -51,7 +51,7 @@ const unsigned int BUFFER_SIZE = 4096;
const bool ALLOW_QIODEVICE_BUFFERING = true; const bool ALLOW_QIODEVICE_BUFFERING = true;
// comment to get trace output: // comment to get trace output:
#define qDebug if(1){}else qDebug //#define qDebug if(1){}else qDebug
namespace { namespace {
class Reader : public QThread { class Reader : public QThread {
@ -188,7 +188,8 @@ Writer::Writer( int fd_, Qt::HANDLE handle_ )
Writer::~Writer() {} Writer::~Writer() {}
class KDPipeIODevice::Private { class KDPipeIODevice::Private : public QObject {
Q_OBJECT
friend class ::KDPipeIODevice; friend class ::KDPipeIODevice;
KDPipeIODevice * const q; KDPipeIODevice * const q;
public: public:
@ -196,6 +197,11 @@ public:
~Private(); ~Private();
bool doOpen( int, Qt::HANDLE, OpenMode ); bool doOpen( int, Qt::HANDLE, OpenMode );
bool startReaderThread();
bool startWriterThread();
void stopThreads();
bool triedToStartReader;
bool triedToStartWriter;
private: private:
int fd; int fd;
@ -205,19 +211,18 @@ private:
}; };
KDPipeIODevice::Private::Private( KDPipeIODevice * qq ) KDPipeIODevice::Private::Private( KDPipeIODevice * qq )
: q( qq ), : QObject( qq ), q( qq ),
fd( -1 ), fd( -1 ),
handle( 0 ), handle( 0 ),
reader( 0 ), reader( 0 ),
writer( 0 ) writer( 0 ),
triedToStartReader( false ), triedToStartWriter( false )
{ {
} }
KDPipeIODevice::Private::~Private() {} KDPipeIODevice::Private::~Private() {}
KDPipeIODevice::KDPipeIODevice( QObject * p ) KDPipeIODevice::KDPipeIODevice( QObject * p )
: QIODevice( p ), d( new Private( this ) ) : QIODevice( p ), d( new Private( this ) )
{ {
@ -267,6 +272,36 @@ bool KDPipeIODevice::open( Qt::HANDLE h, OpenMode mode ) { KDAB_CHECK_THIS;
} }
bool KDPipeIODevice::Private::startReaderThread()
{
if ( triedToStartReader )
return true;
triedToStartReader = true;
if ( reader && !reader->isRunning() && !reader->isFinished() ) {
LOCKED( reader );
reader->start( QThread::HighestPriority );
if ( !reader->hasStarted.wait( &reader->mutex, 1000 ) )
return false;
}
return true;
}
bool KDPipeIODevice::Private::startWriterThread()
{
if ( triedToStartWriter )
return true;
triedToStartWriter = true;
if ( writer && !writer->isRunning() && !writer->isFinished() ) {
LOCKED( writer );
writer->start( QThread::HighestPriority );
if ( !writer->hasStarted.wait( &writer->mutex, 1000 ) )
return false;
}
return true;
}
bool KDPipeIODevice::Private::doOpen( int fd_, Qt::HANDLE handle_, OpenMode mode_ ) { bool KDPipeIODevice::Private::doOpen( int fd_, Qt::HANDLE handle_, OpenMode mode_ ) {
if ( q->isOpen() || fd_ < 0 ) if ( q->isOpen() || fd_ < 0 )
@ -288,19 +323,15 @@ bool KDPipeIODevice::Private::doOpen( int fd_, Qt::HANDLE handle_, OpenMode mode
if ( mode_ & ReadOnly ) { if ( mode_ & ReadOnly ) {
reader_.reset( new Reader( fd_, handle_ ) ); reader_.reset( new Reader( fd_, handle_ ) );
LOCKED( reader_ ); qDebug( "KDPipeIODevice::doOpen: created reader for fd %d", fd_ );
reader_->start( QThread::HighestPriority ); connect( reader_.get(), SIGNAL(readyRead()), q,
if ( !reader_->hasStarted.wait( &reader_->mutex, 1000 ) ) SIGNAL(readyRead()), Qt::QueuedConnection );
return false;
connect( reader_.get(), SIGNAL(readyRead()), q, SIGNAL(readyRead()), Qt::QueuedConnection );
} }
if ( mode_ & WriteOnly ) { if ( mode_ & WriteOnly ) {
writer_.reset( new Writer( fd_, handle_ ) ); writer_.reset( new Writer( fd_, handle_ ) );
LOCKED( writer_ ); qDebug( "KDPipeIODevice::doOpen: created writer for fd %d", fd_ );
writer_->start( QThread::HighestPriority ); connect( writer_.get(), SIGNAL(bytesWritten(qint64)), q, SIGNAL(bytesWritten(qint64)),
if ( !writer_->hasStarted.wait( &writer_->mutex, 1000 ) ) Qt::QueuedConnection );
return false;
connect( writer_.get(), SIGNAL(bytesWritten(qint64)), q, SIGNAL(bytesWritten(qint64)), Qt::QueuedConnection );
} }
// commit to *this: // commit to *this:
@ -310,7 +341,6 @@ bool KDPipeIODevice::Private::doOpen( int fd_, Qt::HANDLE handle_, OpenMode mode
writer = writer_.release(); writer = writer_.release();
q->setOpenMode( mode_|Unbuffered ); q->setOpenMode( mode_|Unbuffered );
return true; return true;
} }
@ -318,18 +348,24 @@ int KDPipeIODevice::descriptor() const { KDAB_CHECK_THIS;
return d->fd; return d->fd;
} }
Qt::HANDLE KDPipeIODevice::handle() const { KDAB_CHECK_THIS; Qt::HANDLE KDPipeIODevice::handle() const { KDAB_CHECK_THIS;
return d->handle; return d->handle;
} }
qint64 KDPipeIODevice::bytesAvailable() const { KDAB_CHECK_THIS; qint64 KDPipeIODevice::bytesAvailable() const { KDAB_CHECK_THIS;
const qint64 base = QIODevice::bytesAvailable(); const qint64 base = QIODevice::bytesAvailable();
if ( !d->triedToStartReader ) {
d->startReaderThread();
return base;
}
if ( d->reader ) if ( d->reader )
synchronized( d->reader ) return base + d->reader->bytesInBuffer(); synchronized( d->reader ) return base + d->reader->bytesInBuffer();
return base; return base;
} }
qint64 KDPipeIODevice::bytesToWrite() const { KDAB_CHECK_THIS; qint64 KDPipeIODevice::bytesToWrite() const { KDAB_CHECK_THIS;
d->startWriterThread();
const qint64 base = QIODevice::bytesToWrite(); const qint64 base = QIODevice::bytesToWrite();
if ( d->writer ) if ( d->writer )
synchronized( d->writer ) return base + d->writer->bytesInBuffer(); synchronized( d->writer ) return base + d->writer->bytesInBuffer();
@ -337,6 +373,7 @@ qint64 KDPipeIODevice::bytesToWrite() const { KDAB_CHECK_THIS;
} }
bool KDPipeIODevice::canReadLine() const { KDAB_CHECK_THIS; bool KDPipeIODevice::canReadLine() const { KDAB_CHECK_THIS;
d->startReaderThread();
if ( QIODevice::canReadLine() ) if ( QIODevice::canReadLine() )
return true; return true;
if ( d->reader ) if ( d->reader )
@ -349,8 +386,9 @@ bool KDPipeIODevice::isSequential() const {
} }
bool KDPipeIODevice::atEnd() const { KDAB_CHECK_THIS; bool KDPipeIODevice::atEnd() const { KDAB_CHECK_THIS;
d->startReaderThread();
if ( !QIODevice::atEnd() ) { if ( !QIODevice::atEnd() ) {
qDebug( "KDPipeIODevice::atEnd returns false since QIODevice::atEnd does (with bytesAvailable=%ld)", static_cast<long>(bytesAvailable()) ); qDebug( "%p: KDPipeIODevice::atEnd returns false since QIODevice::atEnd does (with bytesAvailable=%ld)", this, static_cast<long>(bytesAvailable()) );
return false; return false;
} }
if ( !isOpen() ) if ( !isOpen() )
@ -361,14 +399,15 @@ bool KDPipeIODevice::atEnd() const { KDAB_CHECK_THIS;
const bool eof = ( d->reader->error || d->reader->eof ) && d->reader->bufferEmpty(); const bool eof = ( d->reader->error || d->reader->eof ) && d->reader->bufferEmpty();
if ( !eof ) { if ( !eof ) {
if ( !d->reader->error && !d->reader->eof ) if ( !d->reader->error && !d->reader->eof )
qDebug( "KDPipeIODevice::atEnd returns false since !reader->error && !reader->eof" ); qDebug( "%p: KDPipeIODevice::atEnd returns false since !reader->error && !reader->eof", this );
if ( !d->reader->bufferEmpty() ) if ( !d->reader->bufferEmpty() )
qDebug( "KDPipeIODevice::atEnd returns false since !reader->bufferEmpty()" ); qDebug( "%p: KDPipeIODevice::atEnd returns false since !reader->bufferEmpty()", this );
} }
return eof; return eof;
} }
bool KDPipeIODevice::waitForBytesWritten( int msecs ) { KDAB_CHECK_THIS; bool KDPipeIODevice::waitForBytesWritten( int msecs ) { KDAB_CHECK_THIS;
d->startWriterThread();
Writer * const w = d->writer; Writer * const w = d->writer;
if ( !w ) if ( !w )
return true; return true;
@ -377,6 +416,7 @@ bool KDPipeIODevice::waitForBytesWritten( int msecs ) { KDAB_CHECK_THIS;
} }
bool KDPipeIODevice::waitForReadyRead( int msecs ) { KDAB_CHECK_THIS; bool KDPipeIODevice::waitForReadyRead( int msecs ) { KDAB_CHECK_THIS;
d->startReaderThread();
if ( ALLOW_QIODEVICE_BUFFERING ) { if ( ALLOW_QIODEVICE_BUFFERING ) {
if ( bytesAvailable() > 0 ) if ( bytesAvailable() > 0 )
return true; return true;
@ -389,18 +429,22 @@ bool KDPipeIODevice::waitForReadyRead( int msecs ) { KDAB_CHECK_THIS;
} }
qint64 KDPipeIODevice::readData( char * data, qint64 maxSize ) { KDAB_CHECK_THIS; qint64 KDPipeIODevice::readData( char * data, qint64 maxSize ) { KDAB_CHECK_THIS;
qDebug( "%p: KDPipeIODevice::readData: data=%p, maxSize=%lld", this, data, maxSize );
qDebug( "KDPipeIODevice::readData: data=%p, maxSize=%lld", data, maxSize ); if ( maxSize == 0 )
return 0;
d->startReaderThread();
Reader * const r = d->reader; Reader * const r = d->reader;
assert( r ); assert( r );
//assert( r->isRunning() ); // wrong (might be eof, error) //assert( r->isRunning() ); // wrong (might be eof, error)
assert( data || maxSize == 0 ); assert( data || maxSize == 0 );
assert( maxSize >= 0 ); assert( maxSize >= 0 );
if ( r->eofShortCut ) { if ( r->eofShortCut ) {
qDebug( "KDPipeIODevice::readData: hit eofShortCut, returning 0" ); qDebug( "%p: KDPipeIODevice::readData: hit eofShortCut, returning 0", this );
return 0; return 0;
} }
@ -414,31 +458,31 @@ qint64 KDPipeIODevice::readData( char * data, qint64 maxSize ) { KDAB_CHECK_THIS
LOCKED( r ); LOCKED( r );
if ( /* maxSize > 0 && */ r->bufferEmpty() && !r->error && !r->eof ) { // ### block on maxSize == 0? if ( /* maxSize > 0 && */ r->bufferEmpty() && !r->error && !r->eof ) { // ### block on maxSize == 0?
qDebug( "KDPipeIODevice::readData: waiting for bufferNotEmptyCondition" ); qDebug( "%p: KDPipeIODevice::readData: waiting for bufferNotEmptyCondition", this );
r->bufferNotEmptyCondition.wait( &r->mutex ); r->bufferNotEmptyCondition.wait( &r->mutex );
} }
if ( r->bufferEmpty() ) { if ( r->bufferEmpty() ) {
qDebug( "KDPipeIODevice::readData: got empty buffer, signal eof" ); qDebug( "%p: KDPipeIODevice::readData: got empty buffer, signal eof", this );
// woken with an empty buffer must mean either EOF or error: // woken with an empty buffer must mean either EOF or error:
assert( r->eof || r->error ); assert( r->eof || r->error );
r->eofShortCut = true; r->eofShortCut = true;
return r->eof ? 0 : -1 ; return r->eof ? 0 : -1 ;
} }
qDebug( "KDPipeIODevice::readData: got bufferNotEmptyCondition, trying to read %lld bytes", maxSize ); qDebug( "%p: KDPipeIODevice::readData: got bufferNotEmptyCondition, trying to read %lld bytes", this, maxSize );
const qint64 bytesRead = r->readData( data, maxSize ); const qint64 bytesRead = r->readData( data, maxSize );
qDebug( "KDPipeIODevice::readData: read %lld bytes", bytesRead ); qDebug( "%p: KDPipeIODevice::readData: read %lld bytes", this, bytesRead );
qDebug( "%p (fd=%d): KDPipeIODevice::readData: %s", this, d->fd, data );
return bytesRead; return bytesRead;
} }
qint64 Reader::readData( char * data, qint64 maxSize ) { qint64 Reader::readData( char * data, qint64 maxSize ) {
qint64 numRead = rptr < wptr ? wptr - rptr : sizeof buffer - rptr ; qint64 numRead = rptr < wptr ? wptr - rptr : sizeof buffer - rptr ;
if ( numRead > maxSize ) if ( numRead > maxSize )
numRead = maxSize; numRead = maxSize;
qDebug( "KDPipeIODevice::readData: data=%p, maxSize=%lld; rptr=%u, wptr=%u (bytesInBuffer=%u); -> numRead=%lld", qDebug( "%p: KDPipeIODevice::readData: data=%p, maxSize=%lld; rptr=%u, wptr=%u (bytesInBuffer=%u); -> numRead=%lld", this,
data, maxSize, rptr, wptr, bytesInBuffer(), numRead ); data, maxSize, rptr, wptr, bytesInBuffer(), numRead );
std::memcpy( data, buffer + rptr, numRead ); std::memcpy( data, buffer + rptr, numRead );
@ -446,7 +490,7 @@ qint64 Reader::readData( char * data, qint64 maxSize ) {
rptr = ( rptr + numRead ) % sizeof buffer ; rptr = ( rptr + numRead ) % sizeof buffer ;
if ( !bufferFull() ) { if ( !bufferFull() ) {
qDebug( "KDPipeIODevice::readData: signal bufferNotFullCondition" ); qDebug( "%p: KDPipeIODevice::readData: signal bufferNotFullCondition", this );
bufferNotFullCondition.wakeAll(); bufferNotFullCondition.wakeAll();
} }
@ -454,7 +498,7 @@ qint64 Reader::readData( char * data, qint64 maxSize ) {
} }
qint64 KDPipeIODevice::writeData( const char * data, qint64 size ) { KDAB_CHECK_THIS; qint64 KDPipeIODevice::writeData( const char * data, qint64 size ) { KDAB_CHECK_THIS;
d->startWriterThread();
Writer * const w = d->writer; Writer * const w = d->writer;
assert( w ); assert( w );
@ -476,7 +520,6 @@ qint64 KDPipeIODevice::writeData( const char * data, qint64 size ) { KDAB_CHECK_
} }
qint64 Writer::writeData( const char * data, qint64 size ) { qint64 Writer::writeData( const char * data, qint64 size ) {
assert( bufferEmpty() ); assert( bufferEmpty() );
if ( size > static_cast<qint64>( sizeof buffer ) ) if ( size > static_cast<qint64>( sizeof buffer ) )
@ -492,6 +535,33 @@ qint64 Writer::writeData( const char * data, qint64 size ) {
return size; return size;
} }
void KDPipeIODevice::Private::stopThreads()
{
if ( triedToStartWriter )
{
if ( writer && q->bytesToWrite() > 0 )
q->waitForBytesWritten( -1 );
assert( q->bytesToWrite() == 0 );
}
if ( Reader * & r = reader ) {
synchronized( r ) {
// tell thread to cancel:
r->cancel = true;
// and wake it, so it can terminate:
r->bufferNotFullCondition.wakeAll();
}
}
if ( Writer * & w = writer ) {
synchronized( w ) {
// tell thread to cancel:
w->cancel = true;
// and wake it, so it can terminate:
w->bufferNotEmptyCondition.wakeAll();
}
}
}
void KDPipeIODevice::close() { KDAB_CHECK_THIS; void KDPipeIODevice::close() { KDAB_CHECK_THIS;
if ( !isOpen() ) if ( !isOpen() )
@ -499,32 +569,12 @@ void KDPipeIODevice::close() { KDAB_CHECK_THIS;
// tell clients we're about to close: // tell clients we're about to close:
emit aboutToClose(); emit aboutToClose();
d->stopThreads();
if ( d->writer && bytesToWrite() > 0 ) #define waitAndDelete( t ) if ( t ) { t->wait(); delete t; t = 0; }
waitForBytesWritten( -1 ); waitAndDelete( d->writer );
waitAndDelete( d->reader );
assert( bytesToWrite() == 0 ); #undef waitAndDelete
if ( Reader * & r = d->reader ) {
synchronized( r ) {
// tell thread to cancel:
r->cancel = true;
// and wake it, so it can terminate:
r->bufferNotFullCondition.wakeAll();
}
r->wait();
delete r; r = 0;
}
if ( Writer * & w = d->writer ) {
synchronized( w ) {
// tell thread to cancel:
w->cancel = true;
// and wake it, so it can terminate:
w->bufferNotEmptyCondition.wakeAll();
}
w->wait();
delete w; w = 0;
}
#ifdef Q_OS_WIN32 #ifdef Q_OS_WIN32
CloseHandle( d->handle ); CloseHandle( d->handle );
@ -544,19 +594,19 @@ void Reader::run() {
// too bad QThread doesn't have that itself; a signal isn't enough // too bad QThread doesn't have that itself; a signal isn't enough
hasStarted.wakeAll(); hasStarted.wakeAll();
qDebug( "Reader::run: started" ); qDebug( "%p: Reader::run: started", this );
while ( true ) { while ( true ) {
while ( !cancel && bufferFull() ) { while ( !cancel && bufferFull() ) {
bufferNotEmptyCondition.wakeAll(); bufferNotEmptyCondition.wakeAll();
qDebug( "Reader::run: buffer is full, going to sleep" ); qDebug( "%p: Reader::run: buffer is full, going to sleep", this );
bufferNotFullCondition.wait( &mutex ); bufferNotFullCondition.wait( &mutex );
qDebug( "Reader::run: woke up" ); qDebug( "%p: Reader::run: woke up", this );
} }
if ( cancel ) { if ( cancel ) {
qDebug( "Reader::run: detected cancel" ); qDebug( "%p: Reader::run: detected cancel", this );
goto leave; goto leave;
} }
@ -567,11 +617,11 @@ void Reader::run() {
if ( numBytes > sizeof buffer - wptr ) if ( numBytes > sizeof buffer - wptr )
numBytes = sizeof buffer - wptr; numBytes = sizeof buffer - wptr;
qDebug( "Reader::run: rptr=%d, wptr=%d -> numBytes=%d", rptr, wptr, numBytes ); qDebug( "%p: Reader::run: rptr=%d, wptr=%d -> numBytes=%d", this, rptr, wptr, numBytes );
assert( numBytes > 0 ); assert( numBytes > 0 );
qDebug( "Reader::run: trying to read %d bytes", numBytes ); qDebug( "%p: Reader::run: trying to read %d bytes", this, numBytes );
#ifdef Q_OS_WIN32 #ifdef Q_OS_WIN32
DWORD numRead; DWORD numRead;
mutex.unlock(); mutex.unlock();
@ -580,10 +630,10 @@ void Reader::run() {
if ( !ok ) { if ( !ok ) {
errorCode = static_cast<int>( GetLastError() ); errorCode = static_cast<int>( GetLastError() );
if ( errorCode == ERROR_BROKEN_PIPE ) { if ( errorCode == ERROR_BROKEN_PIPE ) {
qDebug( "Reader::run: got eof" ); qDebug( "%p: Reader::run: got eof (broken pipe)", this );
eof = true; eof = true;
} else { } else {
qDebug( "Reader::run: got error: %d", errorCode ); qDebug( "%p: Reader::run: got error: %s (%d)", this, strerror( errorCode ), errorCode );
error = true; error = true;
} }
goto leave; goto leave;
@ -599,32 +649,33 @@ void Reader::run() {
if ( numRead < 0 ) { if ( numRead < 0 ) {
errorCode = errno; errorCode = errno;
error = true; error = true;
qDebug( "Reader::run: got error: %d", errorCode ); qDebug( "%p: Reader::run: got error: %d", this, errorCode );
goto leave; goto leave;
} }
#endif #endif
qDebug( "Reader::run: read %ld bytes", static_cast<long>(numRead) ); qDebug( "%p: Reader::run: read %ld bytes", this, static_cast<long>(numRead) );
qDebug( "%p (fd=%d): KDPipeIODevice::readData: %s", this, fd, buffer );
if ( numRead == 0 ) { if ( numRead == 0 ) {
qDebug( "Reader::run: eof detected" ); qDebug( "%p: Reader::run: eof detected", this );
eof = true; eof = true;
goto leave; goto leave;
} }
if ( cancel ) { if ( cancel ) {
qDebug( "Reader::run: detected cancel" ); qDebug( "%p: Reader::run: detected cancel", this );
goto leave; goto leave;
} }
qDebug( "Reader::run: buffer before: rptr=%4d, wptr=%4d", rptr, wptr ); qDebug( "%p: Reader::run: buffer before: rptr=%4d, wptr=%4d", this, rptr, wptr );
wptr = ( wptr + numRead ) % sizeof buffer; wptr = ( wptr + numRead ) % sizeof buffer;
qDebug( "Reader::run: buffer after: rptr=%4d, wptr=%4d", rptr, wptr ); qDebug( "%p: Reader::run: buffer after: rptr=%4d, wptr=%4d", this, rptr, wptr );
if ( !bufferEmpty() ) { if ( !bufferEmpty() ) {
qDebug( "Reader::run: buffer no longer empty, waking everyone" ); qDebug( "%p: Reader::run: buffer no longer empty, waking everyone", this );
bufferNotEmptyCondition.wakeAll(); bufferNotEmptyCondition.wakeAll();
emit readyRead(); emit readyRead();
} }
} }
leave: leave:
qDebug( "Reader::run: terminating" ); qDebug( "%p: Reader::run: terminating", this );
bufferNotEmptyCondition.wakeAll(); bufferNotEmptyCondition.wakeAll();
emit readyRead(); emit readyRead();
} }
@ -636,25 +687,25 @@ void Writer::run() {
// too bad QThread doesn't have that itself; a signal isn't enough // too bad QThread doesn't have that itself; a signal isn't enough
hasStarted.wakeAll(); hasStarted.wakeAll();
qDebug( "Writer::run: started" ); qDebug( "%p: Writer::run: started", this );
while ( true ) { while ( true ) {
while ( !cancel && bufferEmpty() ) { while ( !cancel && bufferEmpty() ) {
bufferEmptyCondition.wakeAll(); bufferEmptyCondition.wakeAll();
qDebug( "Writer::run: buffer is empty, going to sleep" ); qDebug( "%p: Writer::run: buffer is empty, going to sleep", this );
bufferNotEmptyCondition.wait( &mutex ); bufferNotEmptyCondition.wait( &mutex );
qDebug( "Writer::run: woke up" ); qDebug( "%p: Writer::run: woke up", this );
} }
if ( cancel ) { if ( cancel ) {
qDebug( "Writer::run: detected cancel" ); qDebug( "%p: Writer::run: detected cancel", this );
goto leave; goto leave;
} }
assert( numBytesInBuffer > 0 ); assert( numBytesInBuffer > 0 );
qDebug( "Writer::run: Trying to write %u bytes", numBytesInBuffer ); qDebug( "%p: Writer::run: Trying to write %u bytes", this, numBytesInBuffer );
qint64 totalWritten = 0; qint64 totalWritten = 0;
do { do {
mutex.unlock(); mutex.unlock();
@ -663,7 +714,7 @@ void Writer::run() {
if ( !WriteFile( handle, buffer + totalWritten, numBytesInBuffer - totalWritten, &numWritten, 0 ) ) { if ( !WriteFile( handle, buffer + totalWritten, numBytesInBuffer - totalWritten, &numWritten, 0 ) ) {
mutex.lock(); mutex.lock();
errorCode = static_cast<int>( GetLastError() ); errorCode = static_cast<int>( GetLastError() );
qDebug( "Writer::run: got error code: %d", errorCode ); qDebug( "%p: Writer::run: got error code: %d", this, errorCode );
error = true; error = true;
goto leave; goto leave;
} }
@ -676,7 +727,7 @@ void Writer::run() {
if ( numWritten < 0 ) { if ( numWritten < 0 ) {
mutex.lock(); mutex.lock();
errorCode = errno; errorCode = errno;
qDebug( "Writer::run: got error code: %d", errorCode ); qDebug( "%p: Writer::run: got error code: %d", this, errorCode );
error = true; error = true;
goto leave; goto leave;
} }
@ -685,14 +736,14 @@ void Writer::run() {
mutex.lock(); mutex.lock();
} while ( totalWritten < numBytesInBuffer ); } while ( totalWritten < numBytesInBuffer );
qDebug( "Writer::run: wrote %lld bytes", totalWritten ); qDebug( "%p: Writer::run: wrote %lld bytes", this, totalWritten );
numBytesInBuffer = 0; numBytesInBuffer = 0;
bufferEmptyCondition.wakeAll(); bufferEmptyCondition.wakeAll();
emit bytesWritten( totalWritten ); emit bytesWritten( totalWritten );
} }
leave: leave:
qDebug( "Writer::run: terminating" ); qDebug( "%p: Writer::run: terminating", this );
numBytesInBuffer = 0; numBytesInBuffer = 0;
bufferEmptyCondition.wakeAll(); bufferEmptyCondition.wakeAll();
emit bytesWritten( 0 ); emit bytesWritten( 0 );

View File

@ -1,8 +1,8 @@
/**************************************************************************** /****************************************************************************
** Meta object code from reading C++ file 'kdpipeiodevice.cpp' ** Meta object code from reading C++ file 'kdpipeiodevice.cpp'
** **
** Created: Mon Aug 27 15:17:18 2007 ** Created: Wed Sep 26 11:05:05 2007
** by: The Qt Meta Object Compiler version 59 (Qt 4.3.0) ** by: The Qt Meta Object Compiler version 59 (Qt 4.3.1)
** **
** WARNING! All changes made in this file will be lost! ** WARNING! All changes made in this file will be lost!
*****************************************************************************/ *****************************************************************************/
@ -10,7 +10,7 @@
#if !defined(Q_MOC_OUTPUT_REVISION) #if !defined(Q_MOC_OUTPUT_REVISION)
#error "The header file 'kdpipeiodevice.cpp' doesn't include <QObject>." #error "The header file 'kdpipeiodevice.cpp' doesn't include <QObject>."
#elif Q_MOC_OUTPUT_REVISION != 59 #elif Q_MOC_OUTPUT_REVISION != 59
#error "This file was generated using the moc from 4.3.0. It" #error "This file was generated using the moc from 4.3.1. It"
#error "cannot be used with the include files from this version of Qt." #error "cannot be used with the include files from this version of Qt."
#error "(The moc has changed too much.)" #error "(The moc has changed too much.)"
#endif #endif
@ -130,3 +130,45 @@ void Writer::bytesWritten(qint64 _t1)
void *_a[] = { 0, const_cast<void*>(reinterpret_cast<const void*>(&_t1)) }; void *_a[] = { 0, const_cast<void*>(reinterpret_cast<const void*>(&_t1)) };
QMetaObject::activate(this, &staticMetaObject, 0, _a); QMetaObject::activate(this, &staticMetaObject, 0, _a);
} }
static const uint qt_meta_data_KDPipeIODevice__Private[] = {
// content:
1, // revision
0, // classname
0, 0, // classinfo
0, 0, // methods
0, 0, // properties
0, 0, // enums/sets
0 // eod
};
static const char qt_meta_stringdata_KDPipeIODevice__Private[] = {
"KDPipeIODevice::Private\0"
};
const QMetaObject KDPipeIODevice::Private::staticMetaObject = {
{ &QObject::staticMetaObject, qt_meta_stringdata_KDPipeIODevice__Private,
qt_meta_data_KDPipeIODevice__Private, 0 }
};
const QMetaObject *KDPipeIODevice::Private::metaObject() const
{
return &staticMetaObject;
}
void *KDPipeIODevice::Private::qt_metacast(const char *_clname)
{
if (!_clname) return 0;
if (!strcmp(_clname, qt_meta_stringdata_KDPipeIODevice__Private))
return static_cast<void*>(const_cast< Private*>(this));
return QObject::qt_metacast(_clname);
}
int KDPipeIODevice::Private::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
{
_id = QObject::qt_metacall(_c, _id, _a);
if (_id < 0)
return _id;
return _id;
}

View File

@ -82,10 +82,18 @@ using _gpgme_::KDPipeIODevice;
really nice callback interfaces to let the user control all this at really nice callback interfaces to let the user control all this at
a per-context level. */ a per-context level. */
#define MAX_SLAFD 50000
#define MAX_SLAFD 256
QIODevice *iodevice_table[MAX_SLAFD]; struct DeviceEntry {
DeviceEntry() : iodev( 0 ), actual_fd( -1 ), refCount( 1 ) {}
QIODevice* iodev;
int actual_fd;
mutable int refCount;
void ref() const { ++refCount; }
int unref() const { return --refCount; }
};
DeviceEntry* iodevice_table[MAX_SLAFD];
static QIODevice * static QIODevice *
@ -95,13 +103,16 @@ find_channel (int fd, int create)
return NULL; return NULL;
if (create && !iodevice_table[fd]) if (create && !iodevice_table[fd])
iodevice_table[fd] = new KDPipeIODevice {
(fd, QIODevice::ReadOnly|QIODevice::Unbuffered); DeviceEntry* entry = new DeviceEntry;
entry->actual_fd = fd;
return iodevice_table[fd]; entry->iodev = new KDPipeIODevice
(fd, QIODevice::ReadWrite|QIODevice::Unbuffered);
iodevice_table[fd] = entry;
}
return iodevice_table[fd] ? iodevice_table[fd]->iodev : 0;
} }
/* Write the printable version of FD to the buffer BUF of length /* Write the printable version of FD to the buffer BUF of length
BUFLEN. The printable version is the representation on the command BUFLEN. The printable version is the representation on the command
line that the child process expects. */ line that the child process expects. */
@ -232,7 +243,9 @@ _gpgme_io_pipe (int filedes[2], int inherit_idx)
/* Now we have a pipe with the right end inheritable. The other end /* Now we have a pipe with the right end inheritable. The other end
should have a giochannel. */ should have a giochannel. */
chan = find_channel (filedes[1 - inherit_idx], 1); chan = find_channel (filedes[1 - inherit_idx], 1);
if (!chan) if (!chan)
{ {
int saved_errno = errno; int saved_errno = errno;
@ -248,7 +261,6 @@ _gpgme_io_pipe (int filedes[2], int inherit_idx)
chan); chan);
} }
int int
_gpgme_io_close (int fd) _gpgme_io_close (int fd)
{ {
@ -270,12 +282,25 @@ _gpgme_io_close (int fd)
} }
/* Then do the close. */ /* Then do the close. */
chan = iodevice_table[fd];
if (chan) DeviceEntry* const entry = iodevice_table[fd];
if ( entry )
{ {
chan->close(); assert( entry->refCount > 0 );
delete chan; const int actual_fd = entry->actual_fd;
iodevice_table[fd] = NULL; assert( actual_fd > 0 );
if ( !entry->unref() ) {
entry->iodev->close();
delete entry->iodev;
delete entry;
for ( int i = 0; i < MAX_SLAFD; ++i ) {
if ( iodevice_table[i] == entry )
iodevice_table[i] = 0;
}
}
if ( fd != actual_fd )
_close( fd );
} }
else else
_close (fd); _close (fd);
@ -586,13 +611,6 @@ _gpgme_io_select (struct io_select_fd_s *fds, size_t nfds, int nonblock)
} }
int
_gpgme_io_dup (int fd)
{
return _dup (fd);
}
/* Look up the qiodevice for file descriptor FD. */ /* Look up the qiodevice for file descriptor FD. */
extern "C" extern "C"
void * void *
@ -610,3 +628,16 @@ gpgme_get_giochannel (int fd)
return NULL; return NULL;
} }
int
_gpgme_io_dup (int fd)
{
const int new_fd = _dup( fd );
iodevice_table[new_fd] = iodevice_table[fd];
if ( iodevice_table[new_fd] )
iodevice_table[new_fd]->ref();
else
find_channel( new_fd, /*create=*/1 );
return new_fd;
}