1
1
// SPDX-License-Identifier: GPL-2.0
2
2
3
- use alloc:: { collections :: btree_map :: BTreeMap , sync:: Arc , vec:: Vec } ;
3
+ use alloc:: { sync:: Arc , vec:: Vec } ;
4
4
use core:: {
5
- mem:: { swap , MaybeUninit } ,
5
+ mem:: { take , MaybeUninit } ,
6
6
ops:: Range ,
7
7
pin:: Pin ,
8
8
} ;
@@ -14,6 +14,7 @@ use kernel::{
14
14
linked_list:: List ,
15
15
pages:: Pages ,
16
16
prelude:: * ,
17
+ rbtree:: RBTree ,
17
18
sync:: { Guard , Mutex , Ref } ,
18
19
user_ptr:: { UserSlicePtr , UserSlicePtrReader } ,
19
20
Error ,
@@ -62,11 +63,11 @@ impl Mapping {
62
63
pub ( crate ) struct ProcessInner {
63
64
is_manager : bool ,
64
65
is_dead : bool ,
65
- threads : BTreeMap < i32 , Arc < Thread > > ,
66
+ threads : RBTree < i32 , Arc < Thread > > ,
66
67
ready_threads : List < Arc < Thread > > ,
67
68
work : List < DeliverToReadListAdapter > ,
68
69
mapping : Option < Mapping > ,
69
- nodes : BTreeMap < usize , Arc < Node > > ,
70
+ nodes : RBTree < usize , Arc < Node > > ,
70
71
71
72
delivered_deaths : List < Arc < NodeDeath > > ,
72
73
@@ -85,11 +86,11 @@ impl ProcessInner {
85
86
Self {
86
87
is_manager : false ,
87
88
is_dead : false ,
88
- threads : BTreeMap :: new ( ) ,
89
+ threads : RBTree :: new ( ) ,
89
90
ready_threads : List :: new ( ) ,
90
91
work : List :: new ( ) ,
91
92
mapping : None ,
92
- nodes : BTreeMap :: new ( ) ,
93
+ nodes : RBTree :: new ( ) ,
93
94
requested_thread_count : 0 ,
94
95
max_threads : 0 ,
95
96
started_thread_count : 0 ,
@@ -260,25 +261,25 @@ impl NodeRefInfo {
260
261
}
261
262
262
263
struct ProcessNodeRefs {
263
- by_handle : BTreeMap < u32 , NodeRefInfo > ,
264
- by_global_id : BTreeMap < u64 , u32 > ,
264
+ by_handle : RBTree < u32 , NodeRefInfo > ,
265
+ by_global_id : RBTree < u64 , u32 > ,
265
266
}
266
267
267
268
impl ProcessNodeRefs {
268
269
fn new ( ) -> Self {
269
270
Self {
270
- by_handle : BTreeMap :: new ( ) ,
271
- by_global_id : BTreeMap :: new ( ) ,
271
+ by_handle : RBTree :: new ( ) ,
272
+ by_global_id : RBTree :: new ( ) ,
272
273
}
273
274
}
274
275
}
275
276
276
277
pub ( crate ) struct Process {
277
278
ctx : Ref < Context > ,
278
279
279
- // TODO: For now this a mutex because we have allocations in BTreeMap and RangeAllocator while
280
- // holding the lock. We may want to split up the process state at some point to use a spin lock
281
- // for the other fields; we can also get rid of allocations in BTreeMap once we replace it .
280
+ // TODO: For now this a mutex because we have allocations in RangeAllocator while holding the
281
+ // lock. We may want to split up the process state at some point to use a spin lock for the
282
+ // other fields.
282
283
// TODO: Make this private again.
283
284
pub ( crate ) inner : Mutex < ProcessInner > ,
284
285
@@ -348,6 +349,7 @@ impl Process {
348
349
349
350
// Allocate a new `Thread` without holding any locks.
350
351
let ta = Thread :: new ( id, self . clone ( ) ) ?;
352
+ let node = RBTree :: try_allocate_node ( id, ta. clone ( ) ) ?;
351
353
352
354
let mut inner = self . inner . lock ( ) ;
353
355
@@ -356,9 +358,7 @@ impl Process {
356
358
return Ok ( thread. clone ( ) ) ;
357
359
}
358
360
359
- // TODO: We need a better solution here. Since this allocates, we cannot do it while
360
- // holding a spinlock because it could block. It could panic too.
361
- inner. threads . insert ( id, ta. clone ( ) ) ;
361
+ inner. threads . insert ( node) ;
362
362
Ok ( ta)
363
363
}
364
364
@@ -407,14 +407,14 @@ impl Process {
407
407
408
408
// Allocate the node before reacquiring the lock.
409
409
let node = Arc :: try_new ( Node :: new ( ptr, cookie, flags, self . clone ( ) ) ) ?;
410
+ let rbnode = RBTree :: try_allocate_node ( ptr, node. clone ( ) ) ?;
410
411
411
412
let mut inner = self . inner . lock ( ) ;
412
413
if let Some ( node) = inner. get_existing_node_ref ( ptr, cookie, strong, thread) ? {
413
414
return Ok ( node) ;
414
415
}
415
416
416
- // TODO: Avoid allocation while holding lock.
417
- inner. nodes . insert ( ptr, node. clone ( ) ) ;
417
+ inner. nodes . insert ( rbnode) ;
418
418
Ok ( inner. new_node_ref ( node, strong, thread) )
419
419
}
420
420
@@ -423,9 +423,25 @@ impl Process {
423
423
node_ref : NodeRef ,
424
424
is_mananger : bool ,
425
425
) -> Result < u32 > {
426
+ {
427
+ let mut refs = self . node_refs . lock ( ) ;
428
+
429
+ // Do a lookup before inserting.
430
+ if let Some ( handle_ref) = refs. by_global_id . get ( & node_ref. node . global_id ) {
431
+ let handle = * handle_ref;
432
+ let info = refs. by_handle . get_mut ( & handle) . unwrap ( ) ;
433
+ info. node_ref . absorb ( node_ref) ;
434
+ return Ok ( handle) ;
435
+ }
436
+ }
437
+
438
+ // Reserve memory for tree nodes.
439
+ let reserve1 = RBTree :: try_reserve_node ( ) ?;
440
+ let reserve2 = RBTree :: try_reserve_node ( ) ?;
441
+
426
442
let mut refs = self . node_refs . lock ( ) ;
427
443
428
- // Do a lookup before inserting .
444
+ // Do a lookup again as node may have been inserted before the lock was reacquired .
429
445
if let Some ( handle_ref) = refs. by_global_id . get ( & node_ref. node . global_id ) {
430
446
let handle = * handle_ref;
431
447
let info = refs. by_handle . get_mut ( & handle) . unwrap ( ) ;
@@ -449,9 +465,10 @@ impl Process {
449
465
if inner. is_dead {
450
466
return Err ( Error :: ESRCH ) ;
451
467
}
452
- // TODO: Two allocations below.
453
- refs. by_global_id . insert ( node_ref. node . global_id , target) ;
454
- refs. by_handle . insert ( target, NodeRefInfo :: new ( node_ref) ) ;
468
+ refs. by_global_id
469
+ . insert ( reserve1. into_node ( node_ref. node . global_id , target) ) ;
470
+ refs. by_handle
471
+ . insert ( reserve2. into_node ( target, NodeRefInfo :: new ( node_ref) ) ) ;
455
472
Ok ( target)
456
473
}
457
474
@@ -853,8 +870,7 @@ impl FileOperations for Process {
853
870
// Drop all references. We do this dance with `swap` to avoid destroying the references
854
871
// while holding the lock.
855
872
let mut refs = obj. node_refs . lock ( ) ;
856
- let mut node_refs = BTreeMap :: new ( ) ;
857
- swap ( & mut refs. by_handle , & mut node_refs) ;
873
+ let mut node_refs = take ( & mut refs. by_handle ) ;
858
874
drop ( refs) ;
859
875
860
876
// Remove all death notifications from the nodes (that belong to a different process).
@@ -870,10 +886,8 @@ impl FileOperations for Process {
870
886
871
887
// Do similar dance for the state lock.
872
888
let mut inner = obj. inner . lock ( ) ;
873
- let mut threads = BTreeMap :: new ( ) ;
874
- let mut nodes = BTreeMap :: new ( ) ;
875
- swap ( & mut inner. threads , & mut threads) ;
876
- swap ( & mut inner. nodes , & mut nodes) ;
889
+ let threads = take ( & mut inner. threads ) ;
890
+ let nodes = take ( & mut inner. nodes ) ;
877
891
drop ( inner) ;
878
892
879
893
// Release all threads.
0 commit comments