11// SPDX-License-Identifier: GPL-2.0
22
3- use alloc:: { collections :: btree_map :: BTreeMap , sync:: Arc , vec:: Vec } ;
3+ use alloc:: { sync:: Arc , vec:: Vec } ;
44use core:: {
5- mem:: { swap , MaybeUninit } ,
5+ mem:: { take , MaybeUninit } ,
66 ops:: Range ,
77 pin:: Pin ,
88} ;
@@ -14,6 +14,7 @@ use kernel::{
1414 linked_list:: List ,
1515 pages:: Pages ,
1616 prelude:: * ,
17+ rbtree:: RBTree ,
1718 sync:: { Guard , Mutex , Ref } ,
1819 user_ptr:: { UserSlicePtr , UserSlicePtrReader } ,
1920 Error ,
@@ -62,11 +63,11 @@ impl Mapping {
6263pub ( crate ) struct ProcessInner {
6364 is_manager : bool ,
6465 is_dead : bool ,
65- threads : BTreeMap < i32 , Arc < Thread > > ,
66+ threads : RBTree < i32 , Arc < Thread > > ,
6667 ready_threads : List < Arc < Thread > > ,
6768 work : List < DeliverToReadListAdapter > ,
6869 mapping : Option < Mapping > ,
69- nodes : BTreeMap < usize , Arc < Node > > ,
70+ nodes : RBTree < usize , Arc < Node > > ,
7071
7172 delivered_deaths : List < Arc < NodeDeath > > ,
7273
@@ -85,11 +86,11 @@ impl ProcessInner {
8586 Self {
8687 is_manager : false ,
8788 is_dead : false ,
88- threads : BTreeMap :: new ( ) ,
89+ threads : RBTree :: new ( ) ,
8990 ready_threads : List :: new ( ) ,
9091 work : List :: new ( ) ,
9192 mapping : None ,
92- nodes : BTreeMap :: new ( ) ,
93+ nodes : RBTree :: new ( ) ,
9394 requested_thread_count : 0 ,
9495 max_threads : 0 ,
9596 started_thread_count : 0 ,
@@ -260,25 +261,25 @@ impl NodeRefInfo {
260261}
261262
262263struct 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 > ,
265266}
266267
267268impl ProcessNodeRefs {
268269 fn new ( ) -> Self {
269270 Self {
270- by_handle : BTreeMap :: new ( ) ,
271- by_global_id : BTreeMap :: new ( ) ,
271+ by_handle : RBTree :: new ( ) ,
272+ by_global_id : RBTree :: new ( ) ,
272273 }
273274 }
274275}
275276
276277pub ( crate ) struct Process {
277278 ctx : Ref < Context > ,
278279
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.
282283 // TODO: Make this private again.
283284 pub ( crate ) inner : Mutex < ProcessInner > ,
284285
@@ -348,6 +349,7 @@ impl Process {
348349
349350 // Allocate a new `Thread` without holding any locks.
350351 let ta = Thread :: new ( id, self . clone ( ) ) ?;
352+ let node = RBTree :: try_allocate_node ( id, ta. clone ( ) ) ?;
351353
352354 let mut inner = self . inner . lock ( ) ;
353355
@@ -356,9 +358,7 @@ impl Process {
356358 return Ok ( thread. clone ( ) ) ;
357359 }
358360
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) ;
362362 Ok ( ta)
363363 }
364364
@@ -407,14 +407,14 @@ impl Process {
407407
408408 // Allocate the node before reacquiring the lock.
409409 let node = Arc :: try_new ( Node :: new ( ptr, cookie, flags, self . clone ( ) ) ) ?;
410+ let rbnode = RBTree :: try_allocate_node ( ptr, node. clone ( ) ) ?;
410411
411412 let mut inner = self . inner . lock ( ) ;
412413 if let Some ( node) = inner. get_existing_node_ref ( ptr, cookie, strong, thread) ? {
413414 return Ok ( node) ;
414415 }
415416
416- // TODO: Avoid allocation while holding lock.
417- inner. nodes . insert ( ptr, node. clone ( ) ) ;
417+ inner. nodes . insert ( rbnode) ;
418418 Ok ( inner. new_node_ref ( node, strong, thread) )
419419 }
420420
@@ -423,9 +423,25 @@ impl Process {
423423 node_ref : NodeRef ,
424424 is_mananger : bool ,
425425 ) -> 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+
426442 let mut refs = self . node_refs . lock ( ) ;
427443
428- // Do a lookup before inserting .
444+ // Do a lookup again as node may have been inserted before the lock was reacquired .
429445 if let Some ( handle_ref) = refs. by_global_id . get ( & node_ref. node . global_id ) {
430446 let handle = * handle_ref;
431447 let info = refs. by_handle . get_mut ( & handle) . unwrap ( ) ;
@@ -449,9 +465,10 @@ impl Process {
449465 if inner. is_dead {
450466 return Err ( Error :: ESRCH ) ;
451467 }
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) ) ) ;
455472 Ok ( target)
456473 }
457474
@@ -853,8 +870,7 @@ impl FileOperations for Process {
853870 // Drop all references. We do this dance with `swap` to avoid destroying the references
854871 // while holding the lock.
855872 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 ) ;
858874 drop ( refs) ;
859875
860876 // Remove all death notifications from the nodes (that belong to a different process).
@@ -870,10 +886,8 @@ impl FileOperations for Process {
870886
871887 // Do similar dance for the state lock.
872888 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 ) ;
877891 drop ( inner) ;
878892
879893 // Release all threads.
0 commit comments