Skip to content

Commit 790c824

Browse files
leon-xdleon-xd
andauthored
fix: passing cache tests when WDK config is enabled (#332)
Co-authored-by: leon-xd <[email protected]>
1 parent b56de53 commit 790c824

File tree

14 files changed

+86
-31
lines changed

14 files changed

+86
-31
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/wdk-macros/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ categories = [
1818
proc-macro = true
1919

2020
[dependencies]
21+
cfg-if.workspace = true
2122
fs4.workspace = true
2223
itertools.workspace = true
2324
proc-macro2.workspace = true

crates/wdk-macros/src/lib.rs

Lines changed: 68 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,25 @@ struct IntermediateOutputASTFragments {
114114
inline_wdf_fn_invocation: ExprCall,
115115
}
116116

117+
/// Struct to represent a file lock guard. This struct enforces RAII, ensuring
118+
/// that the file lock is released when the guard goes out of scope.
119+
struct FileLockGuard {
120+
file: std::fs::File,
121+
}
122+
123+
impl FileLockGuard {
124+
fn new(file: std::fs::File, span: Span) -> Result<Self> {
125+
FileExt::lock_exclusive(&file).to_syn_result(span, "unable to obtain file lock")?;
126+
Ok(Self { file })
127+
}
128+
}
129+
130+
impl Drop for FileLockGuard {
131+
fn drop(&mut self) {
132+
let _ = FileExt::unlock(&self.file);
133+
}
134+
}
135+
117136
impl StringExt for String {
118137
fn to_snake_case(&self) -> String {
119138
// There will be, at max, 2 characters unhandled by the 3-char windows. It is
@@ -406,42 +425,60 @@ fn get_wdf_function_info_map(
406425
types_path: &LitStr,
407426
span: Span,
408427
) -> Result<BTreeMap<String, CachedFunctionInfo>> {
409-
let scratch_dir = scratch::path(concat!(env!("CARGO_CRATE_NAME"), "_ast_fragments"));
410-
let flock = std::fs::File::create(scratch_dir.join(".lock"))
411-
.to_syn_result(span, "unable to create file")?;
428+
cfg_if::cfg_if! {
429+
if #[cfg(test)] {
430+
let scratch_dir = scratch::path(concat!(env!("CARGO_CRATE_NAME"), "_ast_fragments_test"));
431+
} else {
432+
let scratch_dir = scratch::path(concat!(env!("CARGO_CRATE_NAME"), "_ast_fragments"));
433+
}
434+
}
412435

413436
let cached_function_info_map_path = scratch_dir.join("cached_function_info_map.json");
414437

415438
if !cached_function_info_map_path.exists() {
416-
FileExt::lock_exclusive(&flock).to_syn_result(span, "unable to obtain file lock")?;
439+
let flock = std::fs::File::create(scratch_dir.join(".lock"))
440+
.to_syn_result(span, "unable to create file lock")?;
441+
442+
// When _flock_guard goes out of scope, the file lock is released
443+
let _flock_guard = FileLockGuard::new(flock, span)
444+
.to_syn_result(span, "unable to create file lock guard")?;
417445

418446
// Before this thread acquires the lock, it's possible that a concurrent thread
419447
// already created the cache. If so, this thread skips cache generation.
420448
if !cached_function_info_map_path.exists() {
421-
let generated_map = create_wdf_function_info_file_cache(
449+
let function_info_map = create_wdf_function_info_file_cache(
422450
types_path,
423-
&cached_function_info_map_path,
451+
cached_function_info_map_path.as_path(),
424452
span,
425453
)?;
426-
427-
FileExt::unlock(&flock).to_syn_result(span, "unable to unlock file lock")?;
428-
return Ok(generated_map);
454+
return Ok(function_info_map);
429455
}
430-
FileExt::unlock(&flock).to_syn_result(span, "unable to unlock file lock")?;
431456
}
457+
let function_info_map =
458+
read_wdf_function_info_file_cache(cached_function_info_map_path.as_path(), span)?;
459+
Ok(function_info_map)
460+
}
432461

433-
let generated_map_string = std::fs::read_to_string(&cached_function_info_map_path)
462+
/// Reads the cache of function information, then deserializes it into a
463+
/// `BTreeMap`.
464+
fn read_wdf_function_info_file_cache(
465+
cached_function_info_map_path: &std::path::Path,
466+
span: Span,
467+
) -> Result<BTreeMap<String, CachedFunctionInfo>> {
468+
let generated_map_string = std::fs::read_to_string(cached_function_info_map_path)
434469
.to_syn_result(span, "unable to read cache to string")?;
435470
let map: BTreeMap<String, CachedFunctionInfo> = serde_json::from_str(&generated_map_string)
436471
.to_syn_result(span, "unable to parse cache to BTreeMap")?;
437472
Ok(map)
438473
}
439474

440-
/// This function generates the cache of function information, then
475+
/// Generates the cache of function information, then
441476
/// serializes it into a JSON string and writes it to a designated location.
477+
/// Must obtain an exclusive file lock prior to calling this function to prevent
478+
/// concurrent threads from reading and writing to the same file.
442479
fn create_wdf_function_info_file_cache(
443480
types_path: &LitStr,
444-
cached_function_info_map_path: &PathBuf,
481+
cached_function_info_map_path: &std::path::Path,
445482
span: Span,
446483
) -> Result<BTreeMap<String, CachedFunctionInfo>> {
447484
let generated_map = generate_wdf_function_info_file_cache(types_path, span)?;
@@ -452,7 +489,7 @@ fn create_wdf_function_info_file_cache(
452489
Ok(generated_map)
453490
}
454491

455-
/// Parse file from `types_path` to generate a `BTreeMap` of
492+
/// Parses file from `types_path` to generate a `BTreeMap` of
456493
/// function information, where `key` is the function name and `value` is
457494
/// the cached function table information.
458495
fn generate_wdf_function_info_file_cache(
@@ -930,29 +967,31 @@ mod tests {
930967
use super::*;
931968

932969
static SCRATCH_DIR: LazyLock<PathBuf> =
933-
LazyLock::new(|| scratch::path(concat!(env!("CARGO_CRATE_NAME"), "_ast_fragments")));
970+
LazyLock::new(|| scratch::path(concat!(env!("CARGO_CRATE_NAME"), "_ast_fragments_test")));
934971
const CACHE_FILE_NAME: &str = "cached_function_info_map.json";
935972

936-
fn with_file_lock<F>(f: F)
973+
fn with_file_lock_clean_env<F>(f: F)
937974
where
938975
F: FnOnce(),
939976
{
940-
// test flock has to be different than the cache flock since `f` can call
941-
// functions that obtain the cache flock
942-
let test_flock = std::fs::File::create(SCRATCH_DIR.join("test.lock")).unwrap();
943-
let cached_function_info_map_path = SCRATCH_DIR.join(CACHE_FILE_NAME);
944-
977+
let test_flock: std::fs::File =
978+
std::fs::File::create(SCRATCH_DIR.join("test.lock")).unwrap();
945979
FileExt::lock_exclusive(&test_flock).unwrap();
946980

947-
// make sure environment is clean
948-
pretty_assert_eq!(cached_function_info_map_path.exists(), false);
981+
let cached_function_info_map_path = SCRATCH_DIR.join(CACHE_FILE_NAME);
982+
983+
pretty_assert_eq!(
984+
cached_function_info_map_path.exists(),
985+
false,
986+
"could not remove file {}",
987+
cached_function_info_map_path.display()
988+
);
949989

950990
f();
951991

952992
if cached_function_info_map_path.exists() {
953-
std::fs::remove_file(&cached_function_info_map_path).unwrap();
993+
std::fs::remove_file(cached_function_info_map_path).unwrap();
954994
}
955-
pretty_assert_eq!(cached_function_info_map_path.exists(), false);
956995

957996
FileExt::unlock(&test_flock).unwrap();
958997
}
@@ -1126,7 +1165,7 @@ mod tests {
11261165

11271166
#[test]
11281167
fn valid_input() {
1129-
with_file_lock(|| {
1168+
with_file_lock_clean_env(|| {
11301169
let inputs = Inputs {
11311170
types_path: parse_quote! { "tests/unit-tests-input/generated-types.rs" },
11321171
wdf_function_identifier: format_ident!("WdfDriverCreate"),
@@ -1172,7 +1211,7 @@ mod tests {
11721211

11731212
#[test]
11741213
fn valid_input_with_no_arguments() {
1175-
with_file_lock(|| {
1214+
with_file_lock_clean_env(|| {
11761215
let inputs = Inputs {
11771216
types_path: parse_quote! { "tests/unit-tests-input/generated-types.rs" },
11781217
wdf_function_identifier: format_ident!("WdfVerifierDbgBreakPoint"),
@@ -1199,7 +1238,7 @@ mod tests {
11991238

12001239
#[test]
12011240
fn valid_input_no_cache() {
1202-
with_file_lock(|| {
1241+
with_file_lock_clean_env(|| {
12031242
let inputs = Inputs {
12041243
types_path: parse_quote! { "tests/unit-tests-input/generated-types.rs" },
12051244
wdf_function_identifier: format_ident!("WdfVerifierDbgBreakPoint"),
@@ -1241,7 +1280,7 @@ mod tests {
12411280

12421281
#[test]
12431282
fn valid_input_cache_exists() {
1244-
with_file_lock(|| {
1283+
with_file_lock_clean_env(|| {
12451284
let inputs = Inputs {
12461285
types_path: parse_quote! { "tests/unit-tests-input/generated-types.rs" },
12471286
wdf_function_identifier: format_ident!("WdfVerifierDbgBreakPoint"),

crates/wdk-sys/build.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,8 @@ const WDF_FUNCTION_COUNT_DECLARATION_TABLE_INDEX: &str =
5151

5252
static WDF_FUNCTION_COUNT_FUNCTION_TEMPLATE: LazyLock<String> = LazyLock::new(|| {
5353
format!(
54-
r"/// Returns the number of functions available in the WDF function table.
54+
r"#[allow(clippy::must_use_candidate)]
55+
/// Returns the number of functions available in the WDF function table.
5556
/// Should not be used in public API.
5657
pub fn get_wdf_function_count() -> usize {{
5758
{WDF_FUNCTION_COUNT_PLACEHOLDER}

crates/wdk-sys/src/ntddk.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
pub use bindings::*;
1111

1212
#[allow(missing_docs)]
13+
#[allow(clippy::derive_partial_eq_without_eq)]
1314
mod bindings {
1415
#[allow(
1516
clippy::wildcard_imports,

crates/wdk-sys/src/types.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,11 @@ pub use bindings::*;
1010
#[allow(unsafe_op_in_unsafe_fn)]
1111
#[allow(clippy::cast_lossless)]
1212
#[allow(clippy::cast_possible_truncation)]
13+
#[allow(clippy::cast_possible_wrap)]
1314
#[allow(clippy::cognitive_complexity)]
15+
#[allow(clippy::doc_markdown)]
1416
#[allow(clippy::default_trait_access)]
17+
#[allow(clippy::derive_partial_eq_without_eq)]
1518
#[rustversion::attr(
1619
any(
1720
all(not(nightly), before(1.74)),
@@ -26,13 +29,14 @@ pub use bindings::*;
2629
),
2730
allow(clippy::non_canonical_clone_impl)
2831
)]
29-
#[allow(clippy::missing_safety_doc)]
3032
#[allow(clippy::missing_const_for_fn)]
33+
#[allow(clippy::missing_safety_doc)]
3134
#[allow(clippy::module_name_repetitions)]
3235
#[allow(clippy::multiple_unsafe_ops_per_block)]
3336
#[allow(clippy::must_use_candidate)]
3437
#[allow(clippy::not_unsafe_ptr_arg_deref)]
3538
#[allow(clippy::ptr_as_ptr)]
39+
#[allow(clippy::ptr_offset_with_cast)]
3640
#[rustversion::attr(
3741
any(
3842
all(not(nightly), since(1.77)),

examples/sample-kmdf-driver/Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

examples/sample-umdf-driver/Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

examples/sample-wdm-driver/Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/config-kmdf/Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/config-umdf/Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/mixed-package-kmdf-workspace/Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/umdf-driver-workspace/Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/wdk-sys-tests/Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)