Re: K3b 1.0.1 eject problem
Sebastian Trüg <[email protected]>
| Newsgroups | gmane.comp.kde.k3b |
|---|---|
| Message-ID | <[email protected]> |
On Thursday 21 June 2007 17:20:01 [email protected] wrote: > I attach the K3b output (I used the patch: k3b-thread-lock-debug.diff with > plain k3b code, DVD+R VIDEO, no eject) > > I didn't know what I should do with the sr0 device, so I didn't disconnect > it. Thanks a lot. Well, at least I found a flaw in my implementation: the following can happen: thread 1 opens device (K3bDevice::Device::open) thread 2 opens device (K3bDevice::Device::open) thread 1 closes device thread 2 issues command (still thinks device is open) -> crash or at least failure I fixed this with a combination of your patch and some additional changes that make sure that a thread always blocks a whole open-command-close block. The downside is that now open and close are not entirely thread-safe anymore. It is possible to close the device while another thread is issuing a command. I don't know how to solve that properly yet without closing the Device API (I think it can't be done). Anyway, maybe this was the problem all along? I don't know. Could you please test the patch with clean k3b code since here it still works (stupid flawless system! ;) Cheers, Sebastian ------------------------------------------------------------------------- This SF.net email is sponsored by DB2 Express Download DB2 Express C - the FREE version of DB2 express and take control of your XML. No limits. Just data. Click to get it now. http://sourceforge.net/powerbar/db2/ _______________________________________________ K3b-user mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/k3b-user
k3b-thread.diff
(text/x-diff, 13.7 KB)
Index: libk3bdevice/k3bdevice.h
===================================================================
--- libk3bdevice/k3bdevice.h (revision 665632)
+++ libk3bdevice/k3bdevice.h (working copy)
@@ -40,7 +40,7 @@
*
* Devices are constructed by the DeviceManager.
*
- * All methods in Device are thread-safe which basicly means that
+ * All methods except for open and close in Device are thread-safe which basicly means that
* no two commands are sent to the device at the same time.
*/
// FIXME: all methods are const which makes no sense at all!
@@ -454,12 +454,16 @@
* Open the device for access via a file descriptor.
* @return true on success or if the device is already open.
* @see close()
+ *
+ * Be aware that this method is not thread-safe.
*/
bool open( bool write = false ) const;
/**
* Close the files descriptor.
* @see open()
+ *
+ * Be aware that this method is not thread-safe.
*/
void close() const;
@@ -700,6 +704,13 @@
bool getNextWritableAdress( unsigned int& lastSessionStart, unsigned int& nextWritableAdress ) const;
/**
+ * Retrieve the next writable address from the currently mounted writable medium.
+ * \return The next writable address if the medium is empty or appendable or -1
+ * if an error occured.
+ */
+ int nextWritableAddress() const;
+
+ /**
* Locks the device for usage. This means that no MMC command can be performed
* until usageUnlock is called.
*
Index: libk3bdevice/k3bscsicommand_linux.cpp
===================================================================
--- libk3bdevice/k3bscsicommand_linux.cpp (revision 665632)
+++ libk3bdevice/k3bscsicommand_linux.cpp (working copy)
@@ -95,15 +95,20 @@
{
bool needToClose = false;
if( m_device ) {
- if( !m_device->isOpen() ) {
- needToClose = true;
- }
- m_device->open( dir == TR_DIR_WRITE );
- m_deviceHandle = m_device->handle();
+ m_device->usageLock();
+ if( !m_device->isOpen() ) {
+ needToClose = true;
+ }
+ if ( !m_device->open( dir == TR_DIR_WRITE ) ) {
+ m_device->usageUnlock();
+ return -1;
+ }
+ m_deviceHandle = m_device->handle();
}
- if( m_deviceHandle == -1 )
+ if( m_deviceHandle == -1 ) {
return -1;
+ }
int i = -1;
@@ -124,13 +129,7 @@
else
d->sgIo.dxfer_direction = SG_DXFER_NONE;
- if ( m_device ) {
- m_device->usageLock();
- }
i = ::ioctl( m_deviceHandle, SG_IO, &d->sgIo );
- if ( m_device ) {
- m_device->usageUnlock();
- }
if( ( d->sgIo.info&SG_INFO_OK_MASK ) != SG_INFO_OK )
i = -1;
@@ -145,21 +144,19 @@
d->cmd.data_direction = CGC_DATA_WRITE;
else
d->cmd.data_direction = CGC_DATA_NONE;
-
- if ( m_device ) {
- m_device->usageLock();
- }
+
i = ::ioctl( m_deviceHandle, CDROM_SEND_PACKET, &d->cmd );
- if ( m_device ) {
- m_device->usageUnlock();
- }
#ifdef SG_IO
}
-#endif
+#endif
if( needToClose )
m_device->close();
-
+
+ if ( m_device ) {
+ m_device->usageUnlock();
+ }
+
if( i ) {
debugError( d->cmd.cmd[0],
d->sense.error_code,
@@ -167,7 +164,7 @@
d->sense.asc,
d->sense.ascq );
- int errCode =
+ int errCode =
(d->sense.error_code<<24) & 0xF000 |
(d->sense.sense_key<<16) & 0x0F00 |
(d->sense.asc<<8) & 0x00F0 |
Index: libk3bdevice/k3bdevice.cpp
===================================================================
--- libk3bdevice/k3bdevice.cpp (revision 665632)
+++ libk3bdevice/k3bdevice.cpp (working copy)
@@ -176,6 +176,7 @@
bool burnfree;
QMutex mutex;
+ QMutex openCloseMutex;
};
@@ -1342,14 +1343,14 @@
struct cdrom_tochdr tochdr;
struct cdrom_tocentry tocentry;
+ usageLock();
if( open() ) {
//
// CDROMREADTOCHDR ioctl returns:
// cdth_trk0: First Track Number
// cdth_trk1: Last Track Number
//
- usageLock();
- if( ::ioctl(d->deviceFd,CDROMREADTOCHDR,&tochdr) ) {
+ if( ::ioctl( d->deviceFd, CDROMREADTOCHDR, &tochdr ) ) {
k3bDebug() << "(K3bDevice::Device) could not get toc header !" << endl;
success = false;
}
@@ -1384,7 +1385,7 @@
// 2: CD-XA Mode2
//
- if( ::ioctl(d->deviceFd,CDROMREADTOCENTRY,&tocentry) ) {
+ if( ::ioctl( d->deviceFd, CDROMREADTOCENTRY, &tocentry ) ) {
k3bDebug() << "(K3bDevice::Device) error reading tocentry " << i << endl;
success = false;
break;
@@ -1418,7 +1419,6 @@
lastTrack = Track( startSec, startSec, trackType, trackMode );
}
}
- usageUnlock();
if( needToClose )
close();
@@ -1426,6 +1426,8 @@
else
success = false;
+ usageUnlock();
+
return success;
}
#endif // Q_OS_LINUX
@@ -1481,45 +1483,43 @@
// So we use the ioctl on Linux systems
//
#if defined(Q_OS_LINUX)
- bool needToClose = !isOpen();
-
- if( open() ) {
- usageLock();
- bool success = ( ::ioctl( d->deviceFd, CDROM_LOCKDOOR, b ? 1 : 0 ) == 0 );
- usageUnlock();
- if( needToClose )
- close();
- return success;
- }
- else
- return false;
+ bool success = false;
+ bool needToClose = !isOpen();
+ usageLock();
+ if( open() ) {
+ success = ( ::ioctl( d->deviceFd, CDROM_LOCKDOOR, b ? 1 : 0 ) == 0 );
+ if( needToClose )
+ close();
+ }
+ usageUnlock();
+ if ( success )
+ return success;
#elif defined(Q_OS_NETBSD)
- bool needToClose = !isOpen();
- int arg = b ? 1 : 0;
+ bool success = false;
+ bool needToClose = !isOpen();
+ int arg = b ? 1 : 0;
+ usageLock();
+ if( open() ) {
+ success = ( ::ioctl( d->deviceFd, DIOCLOCK, &arg ) == 0 );
+ if( needToClose )
+ close();
+ }
+ usageUnlock();
+ if ( success )
+ return success;
+#endif
- if( open() ) {
- usageLock();
- bool success = ( ::ioctl( d->deviceFd, DIOCLOCK, &arg ) == 0 );
- usageUnlock();
- if( needToClose )
- close();
- return success;
- }
- else
- return false;
-#else
- ScsiCommand cmd( this );
- cmd[0] = MMC_PREVENT_ALLOW_MEDIUM_REMOVAL;
- cmd[5] = 0; // Necessary to set the proper command length
- if( b )
- cmd[4] = 0x01;
- int r = cmd.transport( TR_DIR_WRITE );
+ ScsiCommand cmd( this );
+ cmd[0] = MMC_PREVENT_ALLOW_MEDIUM_REMOVAL;
+ cmd[5] = 0; // Necessary to set the proper command length
+ if( b )
+ cmd[4] = 0x01;
+ int r = cmd.transport( TR_DIR_WRITE );
- if( r )
- k3bDebug() << "(K3bDevice::Device) MMC ALLOW MEDIA REMOVAL failed." << endl;
+ if( r )
+ k3bDebug() << "(K3bDevice::Device) MMC ALLOW MEDIA REMOVAL failed." << endl;
- return ( r == 0 );
-#endif
+ return ( r == 0 );
}
bool K3bDevice::Device::rewritable() const
@@ -1543,90 +1543,90 @@
bool K3bDevice::Device::eject() const
{
#ifdef Q_OS_NETBSD
- bool success = false;
- bool needToClose = !isOpen();
- int arg = 0;
+ bool success = false;
+ bool needToClose = !isOpen();
+ int arg = 0;
- if( open() ) {
- usageLock();
- if ( ::ioctl( d->deviceFd, DIOCEJECT, &arg ) >= 0)
- success = true;
- usageUnlock();
- if( needToClose )
- close();
- }
- if ( success )
- return success;
+ usageLock();
+ if( open() ) {
+ if ( ::ioctl( d->deviceFd, DIOCEJECT, &arg ) >= 0)
+ success = true;
+ if( needToClose )
+ close();
+ }
+ usageUnlock();
+ if ( success )
+ return success;
#elif defined(Q_OS_LINUX)
- bool success = false;
- bool needToClose = !isOpen();
+ bool success = false;
+ bool needToClose = !isOpen();
- if( open() ) {
- usageLock();
+ usageLock();
+ if( open() ) {
if( ::ioctl( d->deviceFd, CDROMEJECT ) >= 0 )
- success = true;
- usageUnlock();
- if( needToClose )
- close();
- }
- if ( success )
- return success;
+ success = true;
+ if( needToClose )
+ close();
+ }
+ usageUnlock();
+ if ( success )
+ return success;
#endif
- ScsiCommand cmd( this );
+ ScsiCommand cmd( this );
cmd[0] = MMC_PREVENT_ALLOW_MEDIUM_REMOVAL;
- cmd[5] = 0; // Necessary to set the proper command length
+ cmd[5] = 0; // Necessary to set the proper command length
cmd.transport();
cmd[0] = MMC_START_STOP_UNIT;
cmd[5] = 0; // Necessary to set the proper command length
- cmd[4] = 0x1; // Start unit
- cmd.transport();
+ cmd[4] = 0x1; // Start unit
+ cmd.transport();
- cmd[4] = 0x2; // LoEj = 1, Start = 0
+ cmd[4] = 0x2; // LoEj = 1, Start = 0
- return !cmd.transport();
+ return !cmd.transport();
}
bool K3bDevice::Device::load() const
{
#ifdef Q_OS_NETBSD
- bool success = false;
- bool needToClose = !isOpen();
- int arg = 0;
+ bool success = false;
+ bool needToClose = !isOpen();
+ int arg = 0;
- if( open() ) {
- usageLock();
- if ( ::ioctl( d->deviceFd, CDIOCCLOSE, &arg ) >= 0)
- success = true;
- usageUnlock();
- if( needToClose )
- close();
- }
- if ( success )
- return success;
+ usageLock();
+ if( open() ) {
+ if ( ::ioctl( d->deviceFd, CDIOCCLOSE, &arg ) >= 0)
+ success = true;
+ if( needToClose )
+ close();
+ }
+ usageUnlock();
+ if ( success )
+ return success;
#elif defined(Q_OS_LINUX)
- bool success = false;
- bool needToClose = !isOpen();
+ bool success = false;
+ bool needToClose = !isOpen();
- if( open() ) {
- usageLock();
+ usageLock();
+ if( open() ) {
if( ::ioctl( d->deviceFd, CDROMCLOSETRAY ) >= 0 )
- success = true;
- usageUnlock();
- if( needToClose )
- close();
- }
- if ( success )
- return success;
+ success = true;
+ if( needToClose )
+ close();
+ }
+ usageUnlock();
+ if ( success )
+ return success;
#endif
- ScsiCommand cmd( this );
- cmd[0] = MMC_START_STOP_UNIT;
- cmd[4] = 0x3; // LoEj = 1, Start = 1
- cmd[5] = 0; // Necessary to set the proper command length
- return !cmd.transport();
+ ScsiCommand cmd( this );
+ cmd[0] = MMC_START_STOP_UNIT;
+ cmd[4] = 0x3; // LoEj = 1, Start = 1
+ cmd[5] = 0; // Necessary to set the proper command length
+ return !cmd.transport();
}
@@ -1636,14 +1636,14 @@
#ifdef Q_OS_LINUX
bool needToClose = !isOpen();
+ usageLock();
if ( open() ) {
- usageLock();
success = ( ::ioctl( d->deviceFd, CDROMEJECT_SW, enabled ? 1 : 0 ) == 0 );
- usageUnlock();
if ( needToClose ) {
close();
}
}
+ usageUnlock();
#endif
return success;
}
@@ -1677,7 +1677,7 @@
if( d->openedReadWrite != write )
close();
- d->mutex.lock();
+ QMutexLocker ml( &d->openCloseMutex );
d->openedReadWrite = write;
@@ -1688,16 +1688,12 @@
<< ((d->cam)?" succeeded.":" failed.") << endl;
}
- d->mutex.unlock();
-
return (d->cam != 0);
#endif
#if defined(Q_OS_LINUX) || defined(Q_OS_NETBSD)
if( d->deviceFd == -1 )
d->deviceFd = openDevice( QFile::encodeName(devicename()), write );
- d->mutex.unlock();
-
return ( d->deviceFd != -1 );
#endif
}
@@ -1705,7 +1701,7 @@
void K3bDevice::Device::close() const
{
- d->mutex.lock();
+ QMutexLocker ml( &d->openCloseMutex );
#ifdef Q_OS_FREEBSD
if( d->cam ) {
@@ -1719,8 +1715,6 @@
d->deviceFd = -1;
}
#endif
-
- d->mutex.unlock();
}
@@ -2200,10 +2194,18 @@
K3b::Msf currentMax;
int currentMaxFormat = 0;
if( readFormatCapacity( 0x26, inf.m_capacity, ¤tMax, ¤tMaxFormat ) ) {
- if( inf.bgFormatState() != BG_FORMAT_NONE )
- inf.m_usedCapacity = currentMax;
- else
- inf.m_usedCapacity = 0;
+ if( currentMaxFormat == 0x1 ) { // unformatted or blank media
+ inf.m_usedCapacity = 0;
+ inf.m_capacity = currentMax;
+ }
+ else {
+ inf.m_usedCapacity = currentMax;
+ // Plextor drives tend to screw things up and report invalid values
+ // for the max format capacity of 1.4 GB DVD media
+ if ( inf.bgFormatState() == BG_FORMAT_COMPLETE ) {
+ inf.m_capacity = currentMax;
+ }
+ }
}
else
k3bDebug() << "(K3bDevice::Device) " << blockDeviceName()
@@ -3535,6 +3537,46 @@
}
+int K3bDevice::Device::nextWritableAddress() const
+{
+ unsigned char* data = 0;
+ unsigned int dataLen = 0;
+ int nwa = -1;
+
+ if( readDiscInformation( &data, dataLen ) ) {
+ disc_info_t* inf = (disc_info_t*)data;
+
+ //
+ // The state of the last session has to be "empty" (0x0) or "incomplete" (0x1)
+ // The procedure here is taken from the dvd+rw-tools and wodim
+ //
+ if( !(inf->border & 0x2) ) {
+ // the incomplete track number is the first track in the last session (the empty session)
+ int nextTrack = inf->first_track_l|inf->first_track_m<<8;
+
+ unsigned char* trackData = 0;
+ unsigned int trackDataLen = 0;
+
+ // Read start address of the incomplete track
+ if( readTrackInformation( &trackData, trackDataLen, 0x1, nextTrack ) ) {
+ nwa = from4Byte( &trackData[8] );
+ delete [] trackData;
+ }
+
+ // Read start address of the invisible track
+ else if ( readTrackInformation( &trackData, trackDataLen, 0x1, 0xff ) ) {
+ nwa = from4Byte( &trackData[8] );
+ delete [] trackData;
+ }
+ }
+
+ delete [] data;
+ }
+
+ return nwa;
+}
+
+
QCString K3bDevice::Device::mediaId( int mediaType ) const
{
QCString id;