Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ git commit --no-verify
### Hardware tests
The MMC tests are ignored by default as they require a CD/DVD drive.
```sh
cargo test -- --include-ignored
cargo test --all-features -- --include-ignored
```

A few of the tests require manual intervention (such as media
Expand All @@ -51,7 +51,7 @@ These are located in [`tests/`](./tests).

Example, to run the media removal test:
```sh
MANUAL_TESTS=1 cargo test -- media_removal --include-ignored
MANUAL_TESTS=1 cargo test --all-features -- media_removal --include-ignored
```

## See also
Expand Down
16 changes: 10 additions & 6 deletions src/cdio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ impl Cdio {

// SAFETY: This invokes cdio_init(), which mutates a static variable.
// CDIO_LAST_DRIVER_LOCK is held to prevent data races.
let _lock = CDIO_LAST_DRIVER_LOCK.lock().unwrap();
let _lock = CDIO_INIT_LOCK.lock().unwrap();
return unsafe { libcdio_sys::cdio_open_am(source, driver, access_mode) };

/// Although prefixed "MMC", this does imply read-write for all
Expand All @@ -67,15 +67,19 @@ impl Deref for Cdio {

impl Drop for Cdio {
fn drop(&mut self) {
let _lock = CDIO_LAST_DRIVER_LOCK.lock().unwrap();
let _lock = CDIO_INIT_LOCK.lock().unwrap();

// SAFETY: This method invokes modifies a static variable.
// CDIO_LAST_DRIVER_LOCK is held to prevent data races.
unsafe { libcdio_sys::cdio_destroy(self.cdio.as_ptr()) }
}
}

/// A lock guarding a private static named `CdIo_last_driver`. It must be held
/// before invoking any libcdio methods that modify this value.
/// As of libcdio v2.3.0, such methods are `cdio_init()` and `cdio_destroy()`.
static CDIO_LAST_DRIVER_LOCK: Mutex<()> = Mutex::new(());
/// A lock that must be held before any routine that initializes or
/// destroys `CdIo_t`.
/// It was found that the GNU/Linux driver initialization routine,
/// is NOT thread safe as of libcdio v2.4.0.
/// Apart from that, this also guards the use of a private static
/// named `CdIo_last_driver`, used by `CdIo_t` during init
/// and cleanup.
pub(crate) static CDIO_INIT_LOCK: Mutex<()> = Mutex::new(());
11 changes: 10 additions & 1 deletion src/drive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,10 @@ use bitflags::bitflags;
use libcdio_sys::cdio_hwinfo_t;
use thiserror::Error;

use crate::cdio::Cdio;
use crate::{
cdio::{CDIO_INIT_LOCK, Cdio},
logging,
};

/// An interface to a disc drive.
pub struct Drive {
Expand All @@ -39,6 +42,12 @@ pub struct Drive {
impl Drive {
/// Returns a list of connected drives.
pub fn drives() -> Vec<PathBuf> {
logging::init_logger();

// SAFETY: This method internally initializes an instance of CdIo_t,
// which is not thread safe. Hold CDIO_INIT_LOCK to uphold thread
// safety.
let _lock = CDIO_INIT_LOCK.lock().unwrap();
let drive_list =
unsafe { libcdio_sys::cdio_get_devices(libcdio_sys::driver_id_t_DRIVER_DEVICE) };
if drive_list.is_null() {
Expand Down
10 changes: 6 additions & 4 deletions tests/media_removal.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
//! Tests that would remove the drive media
use libcdio_rs::{
Mmc,
mmc::{MmcCloseTrayError, MmcError, MmcSenseData, MmcStartStopError, SenseKey},
};

#[cfg(feature = "mmc")]
#[test]
#[ignore = "requires a drive with mmc"]
fn media_removal() {
use libcdio_rs::{
Mmc,
mmc::{MmcCloseTrayError, MmcError, MmcSenseData, MmcStartStopError, SenseKey},
};

if std::env::var("MANUAL_TESTS").is_err() {
return;
}
Expand Down