etest/resource/
manager.rs1use std::collections::HashMap;
2use std::sync::{Arc, RwLock};
3
4use crate::{trace_resources, Location};
5
6use super::{ Resource, ResourceId, ResourceSet, ResourceLockGuard, ResourceManagerNotify };
7
8pub type ResourceEntry = Arc<RwLock<Resource>>;
9
10#[derive(Default)]
11pub struct ResourceManager {
12 resources: HashMap<ResourceId, ResourceEntry>,
13 notify: Arc<ResourceManagerNotify>,
14}
15
16impl ResourceManager {
17 fn find_or_insert_resource(&mut self, id: &ResourceId) -> ResourceEntry {
18 use std::collections::hash_map::Entry as E;
19
20 match self.resources.entry(id.clone()) {
21 E::Occupied(e) => e.get().clone(),
22 E::Vacant(v) => v.insert(Resource::new(id).into()).clone(),
23 }
24 }
25
26 fn try_reserve(&mut self, request: &ResourceSet, owner: &Location) -> Option<ResourceLockGuard> {
27 let mut managed = Vec::new();
28
29 trace_resources!("trying to acquire resources for {}", owner);
30
31 for req in &request.consumes {
36 let entry = self.find_or_insert_resource(req);
37 let entry = entry.read().unwrap();
38
39 if entry.owner.is_some() || !entry.users.is_empty() {
40 trace_resources!(" entry {:?} already owned by {:?} or used by {:?}",
41 entry.id, entry.owner, entry.users);
42 return None;
43 }
44 }
45
46 for req in &request.uses {
47 let entry = self.find_or_insert_resource(req);
48 let entry = entry.read().unwrap();
49
50 if entry.owner.is_some() {
51 trace_resources!(" entry {:?} already owned by {:?}", entry.id, entry.owner);
52 return None;
53 }
54 }
55
56 for req in &request.consumes {
58 let entry = self.resources.get(req).unwrap();
59 managed.push(entry.clone());
60
61 let mut entry = entry.write().unwrap();
62
63 assert!(entry.owner.is_none());
64
65 trace_resources!(" acquired {:?} for ownership", entry.id);
66 entry.owner = Some(owner.clone());
67 }
68
69 for req in &request.uses {
70 let entry = self.resources.get(req).unwrap();
71 managed.push(entry.clone());
72
73 let mut entry = entry.write().unwrap();
74
75 assert!(entry.owner.is_none());
76
77 trace_resources!(" acquired {:?}", entry.id);
78 entry.users.insert(owner.clone());
79 }
80
81 Some(ResourceLockGuard {
82 managed: managed,
83 owner: owner.clone(),
84 notify: self.notify.clone(),
85 })
86 }
87
88 pub fn reserve(this: &RwLock<Self>, request: ResourceSet, owner: &Location) -> ResourceLockGuard {
89 loop {
90 let mut mgr = this.write().unwrap();
93 let token = mgr.notify.token();
94 let resource = mgr.try_reserve(&request, owner);
95
96 drop(mgr);
97
98 match resource {
99 Some(g) => {
100 trace_resources!("resources aquired for {owner}");
101 break g;
102 }
103 None => {
104 trace_resources!("resource not available yet for {owner}; waiting...");
105 let notify = this.read().unwrap().notify.clone();
106
107 notify.wait(token);
111 }
112 }
113 }
114 }
115}