etest/resource/
manager.rs

1use 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        // first step: check whether requested resources are available.
32        //
33        // because they can be reserved only by going through the ResourceManager,
34        // they are available when reserving them later
35        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        // second step: acquire the resources
57        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            // NOTE: do not write this as the match scrutinee; it will hold
91            // the lock during wait() else
92            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                    // do not combine this with above; it will hold the lock
108                    // on 'this' else which might block at the beginning of
109                    // another loop
110                    notify.wait(token);
111                }
112            }
113        }
114    }
115}