diff --git a/gpgme/ChangeLog b/gpgme/ChangeLog index 87557d8a..fc29731e 100644 --- a/gpgme/ChangeLog +++ b/gpgme/ChangeLog @@ -1,3 +1,8 @@ +2007-09-28 Marcus Brinkmann + + * kdpipeiodevice.moc, w32-qt-io.cpp, kdpipeiodevice.cpp: New + versions from Frank Osterfeld. + 2007-09-27 Marcus Brinkmann * w32-glib-io.c (_gpgme_io_spawn), diff --git a/gpgme/kdpipeiodevice.cpp b/gpgme/kdpipeiodevice.cpp index 6f48292a..c0515e36 100644 --- a/gpgme/kdpipeiodevice.cpp +++ b/gpgme/kdpipeiodevice.cpp @@ -51,7 +51,7 @@ const unsigned int BUFFER_SIZE = 4096; const bool ALLOW_QIODEVICE_BUFFERING = true; // comment to get trace output: -#define qDebug if(1){}else qDebug +//#define qDebug if(1){}else qDebug namespace { class Reader : public QThread { @@ -81,7 +81,7 @@ public: return true; return false; } - + Q_SIGNALS: void readyRead(); @@ -188,7 +188,8 @@ Writer::Writer( int fd_, Qt::HANDLE handle_ ) Writer::~Writer() {} -class KDPipeIODevice::Private { +class KDPipeIODevice::Private : public QObject { +Q_OBJECT friend class ::KDPipeIODevice; KDPipeIODevice * const q; public: @@ -196,6 +197,11 @@ public: ~Private(); bool doOpen( int, Qt::HANDLE, OpenMode ); + bool startReaderThread(); + bool startWriterThread(); + void stopThreads(); + bool triedToStartReader; + bool triedToStartWriter; private: int fd; @@ -205,19 +211,18 @@ private: }; KDPipeIODevice::Private::Private( KDPipeIODevice * qq ) - : q( qq ), + : QObject( qq ), q( qq ), fd( -1 ), handle( 0 ), reader( 0 ), - writer( 0 ) + writer( 0 ), + triedToStartReader( false ), triedToStartWriter( false ) { } - KDPipeIODevice::Private::~Private() {} - KDPipeIODevice::KDPipeIODevice( QObject * p ) : 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_ ) { if ( q->isOpen() || fd_ < 0 ) @@ -288,19 +323,15 @@ bool KDPipeIODevice::Private::doOpen( int fd_, Qt::HANDLE handle_, OpenMode mode if ( mode_ & ReadOnly ) { reader_.reset( new Reader( fd_, handle_ ) ); - LOCKED( reader_ ); - reader_->start( QThread::HighestPriority ); - if ( !reader_->hasStarted.wait( &reader_->mutex, 1000 ) ) - return false; - connect( reader_.get(), SIGNAL(readyRead()), q, SIGNAL(readyRead()), Qt::QueuedConnection ); + qDebug( "KDPipeIODevice::doOpen: created reader for fd %d", fd_ ); + connect( reader_.get(), SIGNAL(readyRead()), q, +SIGNAL(readyRead()), Qt::QueuedConnection ); } if ( mode_ & WriteOnly ) { writer_.reset( new Writer( fd_, handle_ ) ); - LOCKED( writer_ ); - writer_->start( QThread::HighestPriority ); - if ( !writer_->hasStarted.wait( &writer_->mutex, 1000 ) ) - return false; - connect( writer_.get(), SIGNAL(bytesWritten(qint64)), q, SIGNAL(bytesWritten(qint64)), Qt::QueuedConnection ); + qDebug( "KDPipeIODevice::doOpen: created writer for fd %d", fd_ ); + connect( writer_.get(), SIGNAL(bytesWritten(qint64)), q, SIGNAL(bytesWritten(qint64)), +Qt::QueuedConnection ); } // commit to *this: @@ -310,7 +341,6 @@ bool KDPipeIODevice::Private::doOpen( int fd_, Qt::HANDLE handle_, OpenMode mode writer = writer_.release(); q->setOpenMode( mode_|Unbuffered ); - return true; } @@ -318,18 +348,24 @@ int KDPipeIODevice::descriptor() const { KDAB_CHECK_THIS; return d->fd; } + Qt::HANDLE KDPipeIODevice::handle() const { KDAB_CHECK_THIS; return d->handle; } qint64 KDPipeIODevice::bytesAvailable() const { KDAB_CHECK_THIS; const qint64 base = QIODevice::bytesAvailable(); + if ( !d->triedToStartReader ) { + d->startReaderThread(); + return base; + } if ( d->reader ) synchronized( d->reader ) return base + d->reader->bytesInBuffer(); return base; } qint64 KDPipeIODevice::bytesToWrite() const { KDAB_CHECK_THIS; + d->startWriterThread(); const qint64 base = QIODevice::bytesToWrite(); if ( d->writer ) synchronized( d->writer ) return base + d->writer->bytesInBuffer(); @@ -337,7 +373,8 @@ qint64 KDPipeIODevice::bytesToWrite() const { KDAB_CHECK_THIS; } bool KDPipeIODevice::canReadLine() const { KDAB_CHECK_THIS; - if ( QIODevice::canReadLine() ) + d->startReaderThread(); + if ( QIODevice::canReadLine() ) return true; if ( d->reader ) synchronized( d->reader ) return d->reader->bufferContains( '\n' ); @@ -349,8 +386,9 @@ bool KDPipeIODevice::isSequential() const { } bool KDPipeIODevice::atEnd() const { KDAB_CHECK_THIS; + d->startReaderThread(); if ( !QIODevice::atEnd() ) { - qDebug( "KDPipeIODevice::atEnd returns false since QIODevice::atEnd does (with bytesAvailable=%ld)", static_cast(bytesAvailable()) ); + qDebug( "%p: KDPipeIODevice::atEnd returns false since QIODevice::atEnd does (with bytesAvailable=%ld)", this, static_cast(bytesAvailable()) ); return false; } 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(); if ( !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() ) - qDebug( "KDPipeIODevice::atEnd returns false since !reader->bufferEmpty()" ); + qDebug( "%p: KDPipeIODevice::atEnd returns false since !reader->bufferEmpty()", this ); } return eof; } bool KDPipeIODevice::waitForBytesWritten( int msecs ) { KDAB_CHECK_THIS; + d->startWriterThread(); Writer * const w = d->writer; if ( !w ) return true; @@ -377,6 +416,7 @@ bool KDPipeIODevice::waitForBytesWritten( int msecs ) { KDAB_CHECK_THIS; } bool KDPipeIODevice::waitForReadyRead( int msecs ) { KDAB_CHECK_THIS; + d->startReaderThread(); if ( ALLOW_QIODEVICE_BUFFERING ) { if ( bytesAvailable() > 0 ) return true; @@ -389,18 +429,22 @@ bool KDPipeIODevice::waitForReadyRead( int msecs ) { 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; assert( r ); + //assert( r->isRunning() ); // wrong (might be eof, error) assert( data || maxSize == 0 ); assert( maxSize >= 0 ); if ( r->eofShortCut ) { - qDebug( "KDPipeIODevice::readData: hit eofShortCut, returning 0" ); + qDebug( "%p: KDPipeIODevice::readData: hit eofShortCut, returning 0", this ); return 0; } @@ -414,31 +458,31 @@ qint64 KDPipeIODevice::readData( char * data, qint64 maxSize ) { KDAB_CHECK_THIS LOCKED( r ); 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 ); } 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: assert( r->eof || r->error ); r->eofShortCut = true; 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 ); - 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; } qint64 Reader::readData( char * data, qint64 maxSize ) { - qint64 numRead = rptr < wptr ? wptr - rptr : sizeof buffer - rptr ; if ( 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 ); std::memcpy( data, buffer + rptr, numRead ); @@ -446,7 +490,7 @@ qint64 Reader::readData( char * data, qint64 maxSize ) { rptr = ( rptr + numRead ) % sizeof buffer ; if ( !bufferFull() ) { - qDebug( "KDPipeIODevice::readData: signal bufferNotFullCondition" ); + qDebug( "%p: KDPipeIODevice::readData: signal bufferNotFullCondition", this ); bufferNotFullCondition.wakeAll(); } @@ -454,7 +498,7 @@ qint64 Reader::readData( char * data, qint64 maxSize ) { } qint64 KDPipeIODevice::writeData( const char * data, qint64 size ) { KDAB_CHECK_THIS; - + d->startWriterThread(); Writer * const w = d->writer; assert( w ); @@ -476,7 +520,6 @@ qint64 KDPipeIODevice::writeData( const char * data, qint64 size ) { KDAB_CHECK_ } qint64 Writer::writeData( const char * data, qint64 size ) { - assert( bufferEmpty() ); if ( size > static_cast( sizeof buffer ) ) @@ -492,6 +535,33 @@ qint64 Writer::writeData( const char * data, qint64 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; if ( !isOpen() ) @@ -499,32 +569,12 @@ void KDPipeIODevice::close() { KDAB_CHECK_THIS; // tell clients we're about to close: emit aboutToClose(); + d->stopThreads(); - if ( d->writer && bytesToWrite() > 0 ) - waitForBytesWritten( -1 ); - - assert( bytesToWrite() == 0 ); - - 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; - } +#define waitAndDelete( t ) if ( t ) { t->wait(); delete t; t = 0; } + waitAndDelete( d->writer ); + waitAndDelete( d->reader ); +#undef waitAndDelete #ifdef Q_OS_WIN32 CloseHandle( d->handle ); @@ -544,19 +594,19 @@ void Reader::run() { // too bad QThread doesn't have that itself; a signal isn't enough hasStarted.wakeAll(); - qDebug( "Reader::run: started" ); + qDebug( "%p: Reader::run: started", this ); while ( true ) { while ( !cancel && bufferFull() ) { 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 ); - qDebug( "Reader::run: woke up" ); + qDebug( "%p: Reader::run: woke up", this ); } if ( cancel ) { - qDebug( "Reader::run: detected cancel" ); + qDebug( "%p: Reader::run: detected cancel", this ); goto leave; } @@ -567,11 +617,11 @@ void Reader::run() { if ( 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 ); - qDebug( "Reader::run: trying to read %d bytes", numBytes ); + qDebug( "%p: Reader::run: trying to read %d bytes", this, numBytes ); #ifdef Q_OS_WIN32 DWORD numRead; mutex.unlock(); @@ -580,10 +630,10 @@ void Reader::run() { if ( !ok ) { errorCode = static_cast( GetLastError() ); if ( errorCode == ERROR_BROKEN_PIPE ) { - qDebug( "Reader::run: got eof" ); + qDebug( "%p: Reader::run: got eof (broken pipe)", this ); eof = true; } else { - qDebug( "Reader::run: got error: %d", errorCode ); + qDebug( "%p: Reader::run: got error: %s (%d)", this, strerror( errorCode ), errorCode ); error = true; } goto leave; @@ -599,32 +649,33 @@ void Reader::run() { if ( numRead < 0 ) { errorCode = errno; error = true; - qDebug( "Reader::run: got error: %d", errorCode ); + qDebug( "%p: Reader::run: got error: %d", this, errorCode ); goto leave; } #endif - qDebug( "Reader::run: read %ld bytes", static_cast(numRead) ); + qDebug( "%p: Reader::run: read %ld bytes", this, static_cast(numRead) ); + qDebug( "%p (fd=%d): KDPipeIODevice::readData: %s", this, fd, buffer ); if ( numRead == 0 ) { - qDebug( "Reader::run: eof detected" ); + qDebug( "%p: Reader::run: eof detected", this ); eof = true; goto leave; } if ( cancel ) { - qDebug( "Reader::run: detected cancel" ); + qDebug( "%p: Reader::run: detected cancel", this ); 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; - 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() ) { - qDebug( "Reader::run: buffer no longer empty, waking everyone" ); + qDebug( "%p: Reader::run: buffer no longer empty, waking everyone", this ); bufferNotEmptyCondition.wakeAll(); emit readyRead(); } } leave: - qDebug( "Reader::run: terminating" ); + qDebug( "%p: Reader::run: terminating", this ); bufferNotEmptyCondition.wakeAll(); emit readyRead(); } @@ -636,25 +687,25 @@ void Writer::run() { // too bad QThread doesn't have that itself; a signal isn't enough hasStarted.wakeAll(); - qDebug( "Writer::run: started" ); + qDebug( "%p: Writer::run: started", this ); while ( true ) { while ( !cancel && bufferEmpty() ) { 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 ); - qDebug( "Writer::run: woke up" ); + qDebug( "%p: Writer::run: woke up", this ); } if ( cancel ) { - qDebug( "Writer::run: detected cancel" ); + qDebug( "%p: Writer::run: detected cancel", this ); goto leave; } 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; do { mutex.unlock(); @@ -663,7 +714,7 @@ void Writer::run() { if ( !WriteFile( handle, buffer + totalWritten, numBytesInBuffer - totalWritten, &numWritten, 0 ) ) { mutex.lock(); errorCode = static_cast( GetLastError() ); - qDebug( "Writer::run: got error code: %d", errorCode ); + qDebug( "%p: Writer::run: got error code: %d", this, errorCode ); error = true; goto leave; } @@ -676,7 +727,7 @@ void Writer::run() { if ( numWritten < 0 ) { mutex.lock(); errorCode = errno; - qDebug( "Writer::run: got error code: %d", errorCode ); + qDebug( "%p: Writer::run: got error code: %d", this, errorCode ); error = true; goto leave; } @@ -685,14 +736,14 @@ void Writer::run() { mutex.lock(); } while ( totalWritten < numBytesInBuffer ); - qDebug( "Writer::run: wrote %lld bytes", totalWritten ); + qDebug( "%p: Writer::run: wrote %lld bytes", this, totalWritten ); numBytesInBuffer = 0; bufferEmptyCondition.wakeAll(); emit bytesWritten( totalWritten ); } leave: - qDebug( "Writer::run: terminating" ); + qDebug( "%p: Writer::run: terminating", this ); numBytesInBuffer = 0; bufferEmptyCondition.wakeAll(); emit bytesWritten( 0 ); diff --git a/gpgme/kdpipeiodevice.moc b/gpgme/kdpipeiodevice.moc index e00d0bce..879ad5a5 100644 --- a/gpgme/kdpipeiodevice.moc +++ b/gpgme/kdpipeiodevice.moc @@ -1,8 +1,8 @@ /**************************************************************************** ** Meta object code from reading C++ file 'kdpipeiodevice.cpp' ** -** Created: Mon Aug 27 15:17:18 2007 -** by: The Qt Meta Object Compiler version 59 (Qt 4.3.0) +** Created: Wed Sep 26 11:05:05 2007 +** by: The Qt Meta Object Compiler version 59 (Qt 4.3.1) ** ** WARNING! All changes made in this file will be lost! *****************************************************************************/ @@ -10,7 +10,7 @@ #if !defined(Q_MOC_OUTPUT_REVISION) #error "The header file 'kdpipeiodevice.cpp' doesn't include ." #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 "(The moc has changed too much.)" #endif @@ -130,3 +130,45 @@ void Writer::bytesWritten(qint64 _t1) void *_a[] = { 0, const_cast(reinterpret_cast(&_t1)) }; 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(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; +} diff --git a/gpgme/w32-qt-io.cpp b/gpgme/w32-qt-io.cpp index 20b537bd..faa9123e 100644 --- a/gpgme/w32-qt-io.cpp +++ b/gpgme/w32-qt-io.cpp @@ -82,10 +82,18 @@ using _gpgme_::KDPipeIODevice; really nice callback interfaces to let the user control all this at a per-context level. */ - -#define MAX_SLAFD 256 +#define MAX_SLAFD 50000 -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 * @@ -95,13 +103,16 @@ find_channel (int fd, int create) return NULL; if (create && !iodevice_table[fd]) - iodevice_table[fd] = new KDPipeIODevice - (fd, QIODevice::ReadOnly|QIODevice::Unbuffered); - - return iodevice_table[fd]; + { + DeviceEntry* entry = new DeviceEntry; + entry->actual_fd = 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 BUFLEN. The printable version is the representation on the command 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 should have a giochannel. */ + chan = find_channel (filedes[1 - inherit_idx], 1); + if (!chan) { int saved_errno = errno; @@ -248,7 +261,6 @@ _gpgme_io_pipe (int filedes[2], int inherit_idx) chan); } - int _gpgme_io_close (int fd) { @@ -270,16 +282,29 @@ _gpgme_io_close (int fd) } /* Then do the close. */ - chan = iodevice_table[fd]; - if (chan) - { - chan->close(); - delete chan; - iodevice_table[fd] = NULL; + + DeviceEntry* const entry = iodevice_table[fd]; + if ( entry ) + { + assert( entry->refCount > 0 ); + const int actual_fd = entry->actual_fd; + 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 _close (fd); - + return 0; } @@ -334,7 +359,7 @@ build_commandline (char **argv) /* The leading double-quote. */ n++; while (*p) - { + { /* An extra one for each literal that must be escaped. */ if (*p == '\\' || *p == '"') n++; @@ -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. */ extern "C" void * @@ -610,3 +628,16 @@ gpgme_get_giochannel (int fd) 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; +} +