1 use super::util::*;
2 use crate::sync::alloc;
3 use crate::Slab;
4 use loom::sync::{Condvar, Mutex};
5 use loom::thread;
6 use std::sync::{
7 atomic::{AtomicBool, Ordering},
8 Arc,
9 };
10
11 #[test]
take_local()12 fn take_local() {
13 run_model("take_local", || {
14 let slab = Arc::new(Slab::new());
15
16 let s = slab.clone();
17 let t1 = thread::spawn(move || {
18 let idx = s.insert(1).expect("insert");
19 assert_eq!(s.get(idx).unwrap(), 1);
20 assert_eq!(s.take(idx), Some(1));
21 assert!(s.get(idx).is_none());
22 let idx = s.insert(2).expect("insert");
23 assert_eq!(s.get(idx).unwrap(), 2);
24 assert_eq!(s.take(idx), Some(2));
25 assert!(s.get(idx).is_none());
26 });
27
28 let s = slab.clone();
29 let t2 = thread::spawn(move || {
30 let idx = s.insert(3).expect("insert");
31 assert_eq!(s.get(idx).unwrap(), 3);
32 assert_eq!(s.take(idx), Some(3));
33 assert!(s.get(idx).is_none());
34 let idx = s.insert(4).expect("insert");
35 assert_eq!(s.get(idx).unwrap(), 4);
36 assert_eq!(s.take(idx), Some(4));
37 assert!(s.get(idx).is_none());
38 });
39
40 let s = slab;
41 let idx1 = s.insert(5).expect("insert");
42 assert_eq!(s.get(idx1).unwrap(), 5);
43 let idx2 = s.insert(6).expect("insert");
44 assert_eq!(s.get(idx2).unwrap(), 6);
45 assert_eq!(s.take(idx1), Some(5));
46 assert!(s.get(idx1).is_none());
47 assert_eq!(s.get(idx2).unwrap(), 6);
48 assert_eq!(s.take(idx2), Some(6));
49 assert!(s.get(idx2).is_none());
50
51 t1.join().expect("thread 1 should not panic");
52 t2.join().expect("thread 2 should not panic");
53 });
54 }
55
56 #[test]
take_remote()57 fn take_remote() {
58 run_model("take_remote", || {
59 let slab = Arc::new(Slab::new());
60
61 let idx1 = slab.insert(1).expect("insert");
62 assert_eq!(slab.get(idx1).unwrap(), 1);
63 let idx2 = slab.insert(2).expect("insert");
64 assert_eq!(slab.get(idx2).unwrap(), 2);
65
66 let idx3 = slab.insert(3).expect("insert");
67 assert_eq!(slab.get(idx3).unwrap(), 3);
68
69 let s = slab.clone();
70 let t1 = thread::spawn(move || {
71 assert_eq!(s.get(idx2).unwrap(), 2);
72 assert_eq!(s.take(idx2), Some(2));
73 });
74
75 let s = slab.clone();
76 let t2 = thread::spawn(move || {
77 assert_eq!(s.get(idx3).unwrap(), 3);
78 assert_eq!(s.take(idx3), Some(3));
79 });
80
81 t1.join().expect("thread 1 should not panic");
82 t2.join().expect("thread 2 should not panic");
83
84 assert_eq!(slab.get(idx1).unwrap(), 1);
85 assert!(slab.get(idx2).is_none());
86 assert!(slab.get(idx3).is_none());
87 });
88 }
89
90 #[test]
racy_take()91 fn racy_take() {
92 run_model("racy_take", || {
93 let slab = Arc::new(Slab::new());
94
95 let idx = slab.insert(1).expect("insert");
96 assert_eq!(slab.get(idx).unwrap(), 1);
97
98 let s1 = slab.clone();
99 let s2 = slab.clone();
100
101 let t1 = thread::spawn(move || s1.take(idx));
102 let t2 = thread::spawn(move || s2.take(idx));
103
104 let r1 = t1.join().expect("thread 1 should not panic");
105 let r2 = t2.join().expect("thread 2 should not panic");
106
107 assert!(
108 r1.is_none() || r2.is_none(),
109 "both threads should not have removed the value"
110 );
111 assert_eq!(
112 r1.or(r2),
113 Some(1),
114 "one thread should have removed the value"
115 );
116 assert!(slab.get(idx).is_none());
117 });
118 }
119
120 #[test]
racy_take_local()121 fn racy_take_local() {
122 run_model("racy_take_local", || {
123 let slab = Arc::new(Slab::new());
124
125 let idx = slab.insert(1).expect("insert");
126 assert_eq!(slab.get(idx).unwrap(), 1);
127
128 let s = slab.clone();
129 let t2 = thread::spawn(move || s.take(idx));
130 let r1 = slab.take(idx);
131 let r2 = t2.join().expect("thread 2 should not panic");
132
133 assert!(
134 r1.is_none() || r2.is_none(),
135 "both threads should not have removed the value"
136 );
137 assert!(
138 r1.or(r2).is_some(),
139 "one thread should have removed the value"
140 );
141 assert!(slab.get(idx).is_none());
142 });
143 }
144
145 #[test]
concurrent_insert_take()146 fn concurrent_insert_take() {
147 run_model("concurrent_insert_remove", || {
148 let slab = Arc::new(Slab::new());
149 let pair = Arc::new((Mutex::new(None), Condvar::new()));
150
151 let slab2 = slab.clone();
152 let pair2 = pair.clone();
153 let remover = thread::spawn(move || {
154 let (lock, cvar) = &*pair2;
155 for i in 0..2 {
156 test_println!("--- remover i={} ---", i);
157 let mut next = lock.lock().unwrap();
158 while next.is_none() {
159 next = cvar.wait(next).unwrap();
160 }
161 let key = next.take().unwrap();
162 assert_eq!(slab2.take(key), Some(i));
163 cvar.notify_one();
164 }
165 });
166
167 let (lock, cvar) = &*pair;
168 for i in 0..2 {
169 test_println!("--- inserter i={} ---", i);
170 let key = slab.insert(i).expect("insert");
171
172 let mut next = lock.lock().unwrap();
173 *next = Some(key);
174 cvar.notify_one();
175
176 // Wait for the item to be removed.
177 while next.is_some() {
178 next = cvar.wait(next).unwrap();
179 }
180
181 assert!(slab.get(key).is_none());
182 }
183
184 remover.join().unwrap();
185 })
186 }
187
188 #[test]
take_remote_and_reuse()189 fn take_remote_and_reuse() {
190 run_model("take_remote_and_reuse", || {
191 let slab = Arc::new(Slab::new_with_config::<TinyConfig>());
192
193 let idx1 = slab.insert(1).expect("insert");
194 let idx2 = slab.insert(2).expect("insert");
195 let idx3 = slab.insert(3).expect("insert");
196 let idx4 = slab.insert(4).expect("insert");
197
198 assert_eq!(slab.get(idx1).unwrap(), 1, "slab: {:#?}", slab);
199 assert_eq!(slab.get(idx2).unwrap(), 2, "slab: {:#?}", slab);
200 assert_eq!(slab.get(idx3).unwrap(), 3, "slab: {:#?}", slab);
201 assert_eq!(slab.get(idx4).unwrap(), 4, "slab: {:#?}", slab);
202
203 let s = slab.clone();
204 let t1 = thread::spawn(move || {
205 assert_eq!(s.take(idx1), Some(1), "slab: {:#?}", s);
206 });
207
208 let idx1 = slab.insert(5).expect("insert");
209 t1.join().expect("thread 1 should not panic");
210
211 assert_eq!(slab.get(idx1).unwrap(), 5, "slab: {:#?}", slab);
212 assert_eq!(slab.get(idx2).unwrap(), 2, "slab: {:#?}", slab);
213 assert_eq!(slab.get(idx3).unwrap(), 3, "slab: {:#?}", slab);
214 assert_eq!(slab.get(idx4).unwrap(), 4, "slab: {:#?}", slab);
215 });
216 }
217
store_when_free<C: crate::Config>(slab: &Arc<Slab<usize, C>>, t: usize) -> usize218 fn store_when_free<C: crate::Config>(slab: &Arc<Slab<usize, C>>, t: usize) -> usize {
219 loop {
220 test_println!("try store {:?}", t);
221 if let Some(key) = slab.insert(t) {
222 test_println!("inserted at {:#x}", key);
223 return key;
224 }
225 test_println!("retrying; slab is full...");
226 thread::yield_now();
227 }
228 }
229
230 struct TinierConfig;
231
232 impl crate::Config for TinierConfig {
233 const INITIAL_PAGE_SIZE: usize = 2;
234 const MAX_PAGES: usize = 1;
235 }
236
237 #[test]
concurrent_remove_remote_and_reuse()238 fn concurrent_remove_remote_and_reuse() {
239 let mut model = loom::model::Builder::new();
240 model.max_branches = 100000;
241 run_builder("concurrent_remove_remote_and_reuse", model, || {
242 let slab = Arc::new(Slab::new_with_config::<TinierConfig>());
243
244 let idx1 = slab.insert(1).unwrap();
245 let idx2 = slab.insert(2).unwrap();
246
247 assert_eq!(slab.get(idx1).unwrap(), 1, "slab: {:#?}", slab);
248 assert_eq!(slab.get(idx2).unwrap(), 2, "slab: {:#?}", slab);
249
250 let s = slab.clone();
251 let s2 = slab.clone();
252
253 let t1 = thread::spawn(move || {
254 s.take(idx1).expect("must remove");
255 });
256
257 let t2 = thread::spawn(move || {
258 s2.take(idx2).expect("must remove");
259 });
260
261 let idx3 = store_when_free(&slab, 3);
262 t1.join().expect("thread 1 should not panic");
263 t2.join().expect("thread 1 should not panic");
264
265 assert!(slab.get(idx1).is_none(), "slab: {:#?}", slab);
266 assert!(slab.get(idx2).is_none(), "slab: {:#?}", slab);
267 assert_eq!(slab.get(idx3).unwrap(), 3, "slab: {:#?}", slab);
268 });
269 }
270
271 struct SetDropped {
272 val: usize,
273 dropped: std::sync::Arc<AtomicBool>,
274 }
275
276 struct AssertDropped {
277 dropped: std::sync::Arc<AtomicBool>,
278 }
279
280 impl AssertDropped {
new(val: usize) -> (Self, SetDropped)281 fn new(val: usize) -> (Self, SetDropped) {
282 let dropped = std::sync::Arc::new(AtomicBool::new(false));
283 let val = SetDropped {
284 val,
285 dropped: dropped.clone(),
286 };
287 (Self { dropped }, val)
288 }
289
assert_dropped(&self)290 fn assert_dropped(&self) {
291 assert!(
292 self.dropped.load(Ordering::SeqCst),
293 "value should have been dropped!"
294 );
295 }
296 }
297
298 impl Drop for SetDropped {
drop(&mut self)299 fn drop(&mut self) {
300 self.dropped.store(true, Ordering::SeqCst);
301 }
302 }
303
304 #[test]
remove_local()305 fn remove_local() {
306 run_model("remove_local", || {
307 let slab = Arc::new(Slab::new_with_config::<TinyConfig>());
308 let slab2 = slab.clone();
309
310 let (dropped, item) = AssertDropped::new(1);
311 let idx = slab.insert(item).expect("insert");
312
313 let guard = slab.get(idx).unwrap();
314
315 assert!(slab.remove(idx));
316
317 let t1 = thread::spawn(move || {
318 let g = slab2.get(idx);
319 drop(g);
320 });
321
322 assert!(slab.get(idx).is_none());
323
324 t1.join().expect("thread 1 should not panic");
325
326 drop(guard);
327 assert!(slab.get(idx).is_none());
328 dropped.assert_dropped();
329 })
330 }
331
332 #[test]
remove_remote()333 fn remove_remote() {
334 run_model("remove_remote", || {
335 let slab = Arc::new(Slab::new_with_config::<TinyConfig>());
336 let slab2 = slab.clone();
337
338 let (dropped, item) = AssertDropped::new(1);
339 let idx = slab.insert(item).expect("insert");
340
341 assert!(slab.remove(idx));
342 let t1 = thread::spawn(move || {
343 let g = slab2.get(idx);
344 drop(g);
345 });
346
347 t1.join().expect("thread 1 should not panic");
348
349 assert!(slab.get(idx).is_none());
350 dropped.assert_dropped();
351 });
352 }
353
354 #[test]
remove_remote_during_insert()355 fn remove_remote_during_insert() {
356 run_model("remove_remote_during_insert", || {
357 let slab = Arc::new(Slab::new_with_config::<TinyConfig>());
358 let slab2 = slab.clone();
359
360 let (dropped, item) = AssertDropped::new(1);
361 let idx = slab.insert(item).expect("insert");
362
363 let t1 = thread::spawn(move || {
364 let g = slab2.get(idx);
365 assert_ne!(g.as_ref().map(|v| v.val), Some(2));
366 drop(g);
367 });
368
369 let (_, item) = AssertDropped::new(2);
370 assert!(slab.remove(idx));
371 let idx2 = slab.insert(item).expect("insert");
372
373 t1.join().expect("thread 1 should not panic");
374
375 assert!(slab.get(idx).is_none());
376 assert!(slab.get(idx2).is_some());
377 dropped.assert_dropped();
378 });
379 }
380
381 #[test]
unique_iter()382 fn unique_iter() {
383 run_model("unique_iter", || {
384 let mut slab = Arc::new(Slab::new());
385
386 let s = slab.clone();
387 let t1 = thread::spawn(move || {
388 s.insert(1).expect("insert");
389 s.insert(2).expect("insert");
390 });
391
392 let s = slab.clone();
393 let t2 = thread::spawn(move || {
394 s.insert(3).expect("insert");
395 s.insert(4).expect("insert");
396 });
397
398 t1.join().expect("thread 1 should not panic");
399 t2.join().expect("thread 2 should not panic");
400
401 let slab = Arc::get_mut(&mut slab).expect("other arcs should be dropped");
402 let items: Vec<_> = slab.unique_iter().map(|&i| i).collect();
403 assert!(items.contains(&1), "items: {:?}", items);
404 assert!(items.contains(&2), "items: {:?}", items);
405 assert!(items.contains(&3), "items: {:?}", items);
406 assert!(items.contains(&4), "items: {:?}", items);
407 });
408 }
409
410 #[test]
custom_page_sz()411 fn custom_page_sz() {
412 let mut model = loom::model::Builder::new();
413 model.max_branches = 100000;
414 model.check(|| {
415 let slab = Slab::<usize>::new_with_config::<TinyConfig>();
416
417 for i in 0..1024usize {
418 test_println!("{}", i);
419 let k = slab.insert(i).expect("insert");
420 let v = slab.get(k).expect("get");
421 assert_eq!(v, i, "slab: {:#?}", slab);
422 }
423 });
424 }
425
426 #[test]
max_refs()427 fn max_refs() {
428 struct LargeGenConfig;
429
430 // Configure the slab with a very large number of bits for the generation
431 // counter. That way, there will be very few bits for the ref count left
432 // over, and this test won't have to malloc millions of references.
433 impl crate::cfg::Config for LargeGenConfig {
434 const INITIAL_PAGE_SIZE: usize = 2;
435 const MAX_THREADS: usize = 32;
436 const MAX_PAGES: usize = 2;
437 }
438
439 let mut model = loom::model::Builder::new();
440 model.max_branches = 100000;
441 model.check(|| {
442 let slab = Slab::new_with_config::<LargeGenConfig>();
443 let key = slab.insert("hello world").unwrap();
444 let max = crate::page::slot::RefCount::<LargeGenConfig>::MAX;
445
446 // Create the maximum number of concurrent references to the entry.
447 let mut refs = (0..max)
448 .map(|_| slab.get(key).unwrap())
449 // Store the refs in a vec so they don't get dropped immediately.
450 .collect::<Vec<_>>();
451
452 assert!(slab.get(key).is_none());
453
454 // After dropping a ref, we should now be able to access the slot again.
455 drop(refs.pop());
456 let ref1 = slab.get(key);
457 assert!(ref1.is_some());
458
459 // Ref1 should max out the number of references again.
460 assert!(slab.get(key).is_none());
461 })
462 }
463
464 mod free_list_reuse {
465 use super::*;
466 struct TinyConfig;
467
468 impl crate::cfg::Config for TinyConfig {
469 const INITIAL_PAGE_SIZE: usize = 2;
470 }
471
472 #[test]
local_remove()473 fn local_remove() {
474 run_model("free_list_reuse::local_remove", || {
475 let slab = Slab::new_with_config::<TinyConfig>();
476
477 let t1 = slab.insert("hello").expect("insert");
478 let t2 = slab.insert("world").expect("insert");
479 assert_eq!(
480 crate::page::indices::<TinyConfig>(t1).1,
481 0,
482 "1st slot should be on 0th page"
483 );
484 assert_eq!(
485 crate::page::indices::<TinyConfig>(t2).1,
486 0,
487 "2nd slot should be on 0th page"
488 );
489 let t3 = slab.insert("earth").expect("insert");
490 assert_eq!(
491 crate::page::indices::<TinyConfig>(t3).1,
492 1,
493 "3rd slot should be on 1st page"
494 );
495
496 slab.remove(t2);
497 let t4 = slab.insert("universe").expect("insert");
498 assert_eq!(
499 crate::page::indices::<TinyConfig>(t4).1,
500 0,
501 "2nd slot should be reused (0th page)"
502 );
503
504 slab.remove(t1);
505 let _ = slab.insert("goodbye").expect("insert");
506 assert_eq!(
507 crate::page::indices::<TinyConfig>(t4).1,
508 0,
509 "1st slot should be reused (0th page)"
510 );
511 });
512 }
513
514 #[test]
local_take()515 fn local_take() {
516 run_model("free_list_reuse::local_take", || {
517 let slab = Slab::new_with_config::<TinyConfig>();
518
519 let t1 = slab.insert("hello").expect("insert");
520 let t2 = slab.insert("world").expect("insert");
521 assert_eq!(
522 crate::page::indices::<TinyConfig>(t1).1,
523 0,
524 "1st slot should be on 0th page"
525 );
526 assert_eq!(
527 crate::page::indices::<TinyConfig>(t2).1,
528 0,
529 "2nd slot should be on 0th page"
530 );
531 let t3 = slab.insert("earth").expect("insert");
532 assert_eq!(
533 crate::page::indices::<TinyConfig>(t3).1,
534 1,
535 "3rd slot should be on 1st page"
536 );
537
538 assert_eq!(slab.take(t2), Some("world"));
539 let t4 = slab.insert("universe").expect("insert");
540 assert_eq!(
541 crate::page::indices::<TinyConfig>(t4).1,
542 0,
543 "2nd slot should be reused (0th page)"
544 );
545
546 assert_eq!(slab.take(t1), Some("hello"));
547 let _ = slab.insert("goodbye").expect("insert");
548 assert_eq!(
549 crate::page::indices::<TinyConfig>(t4).1,
550 0,
551 "1st slot should be reused (0th page)"
552 );
553 });
554 }
555 }
556
557 #[test]
vacant_entry()558 fn vacant_entry() {
559 run_model("vacant_entry", || {
560 let slab = Arc::new(Slab::new());
561 let entry = slab.vacant_entry().unwrap();
562 let key: usize = entry.key();
563
564 let slab2 = slab.clone();
565 let t1 = thread::spawn(move || {
566 test_dbg!(slab2.get(key));
567 });
568
569 entry.insert("hello world");
570 t1.join().unwrap();
571
572 assert_eq!(slab.get(key).expect("get"), "hello world");
573 });
574 }
575
576 #[test]
vacant_entry_2()577 fn vacant_entry_2() {
578 run_model("vacant_entry_2", || {
579 let slab = Arc::new(Slab::new());
580 let entry = slab.vacant_entry().unwrap();
581 let key: usize = entry.key();
582
583 let slab2 = slab.clone();
584 let slab3 = slab.clone();
585 let t1 = thread::spawn(move || {
586 test_dbg!(slab2.get(key));
587 });
588
589 entry.insert("hello world");
590 let t2 = thread::spawn(move || {
591 test_dbg!(slab3.get(key));
592 });
593
594 t1.join().unwrap();
595 t2.join().unwrap();
596 assert_eq!(slab.get(key).expect("get"), "hello world");
597 });
598 }
599
600 #[test]
vacant_entry_remove()601 fn vacant_entry_remove() {
602 run_model("vacant_entry_remove", || {
603 let slab = Arc::new(Slab::new());
604 let entry = slab.vacant_entry().unwrap();
605 let key: usize = entry.key();
606
607 let slab2 = slab.clone();
608 let t1 = thread::spawn(move || {
609 assert!(!slab2.remove(key));
610 });
611
612 t1.join().unwrap();
613
614 entry.insert("hello world");
615 assert_eq!(slab.get(key).expect("get"), "hello world");
616 });
617 }
618
619 #[test]
owned_entry_send_out_of_local()620 fn owned_entry_send_out_of_local() {
621 run_model("owned_entry_send_out_of_local", || {
622 let slab = Arc::new(Slab::<alloc::Track<String>>::new());
623 let key1 = slab
624 .insert(alloc::Track::new(String::from("hello")))
625 .expect("insert item 1");
626 let key2 = slab
627 .insert(alloc::Track::new(String::from("goodbye")))
628 .expect("insert item 2");
629
630 let item1 = slab.clone().get_owned(key1).expect("get key1");
631 let item2 = slab.clone().get_owned(key2).expect("get key2");
632 let slab2 = slab.clone();
633
634 test_dbg!(slab.remove(key1));
635
636 let t1 = thread::spawn(move || {
637 assert_eq!(item1.get_ref(), &String::from("hello"));
638 drop(item1);
639 });
640 let t2 = thread::spawn(move || {
641 assert_eq!(item2.get_ref(), &String::from("goodbye"));
642 test_dbg!(slab2.remove(key2));
643 drop(item2);
644 });
645
646 t1.join().unwrap();
647 t2.join().unwrap();
648
649 assert!(slab.get(key1).is_none());
650 assert!(slab.get(key2).is_none());
651 });
652 }
653
654 #[test]
owned_entrys_outlive_slab()655 fn owned_entrys_outlive_slab() {
656 run_model("owned_entrys_outlive_slab", || {
657 let slab = Arc::new(Slab::<alloc::Track<String>>::new());
658 let key1 = slab
659 .insert(alloc::Track::new(String::from("hello")))
660 .expect("insert item 1");
661 let key2 = slab
662 .insert(alloc::Track::new(String::from("goodbye")))
663 .expect("insert item 2");
664
665 let item1_1 = slab.clone().get_owned(key1).expect("get key1");
666 let item1_2 = slab.clone().get_owned(key1).expect("get key1 again");
667 let item2 = slab.clone().get_owned(key2).expect("get key2");
668 drop(slab);
669
670 let t1 = thread::spawn(move || {
671 assert_eq!(item1_1.get_ref(), &String::from("hello"));
672 drop(item1_1);
673 });
674
675 let t2 = thread::spawn(move || {
676 assert_eq!(item2.get_ref(), &String::from("goodbye"));
677 drop(item2);
678 });
679
680 t1.join().unwrap();
681 t2.join().unwrap();
682
683 assert_eq!(item1_2.get_ref(), &String::from("hello"));
684 });
685 }
686
687 #[test]
owned_entry_ping_pong()688 fn owned_entry_ping_pong() {
689 run_model("owned_entry_ping_pong", || {
690 let slab = Arc::new(Slab::<alloc::Track<String>>::new());
691 let key1 = slab
692 .insert(alloc::Track::new(String::from("hello")))
693 .expect("insert item 1");
694 let key2 = slab
695 .insert(alloc::Track::new(String::from("world")))
696 .expect("insert item 2");
697
698 let item1 = slab.clone().get_owned(key1).expect("get key1");
699 let slab2 = slab.clone();
700 let slab3 = slab.clone();
701
702 let t1 = thread::spawn(move || {
703 assert_eq!(item1.get_ref(), &String::from("hello"));
704 slab2.remove(key1);
705 item1
706 });
707
708 let t2 = thread::spawn(move || {
709 let item2 = slab3.clone().get_owned(key2).unwrap();
710 assert_eq!(item2.get_ref(), &String::from("world"));
711 slab3.remove(key1);
712 item2
713 });
714
715 let item1 = t1.join().unwrap();
716 let item2 = t2.join().unwrap();
717
718 assert_eq!(item1.get_ref(), &String::from("hello"));
719 assert_eq!(item2.get_ref(), &String::from("world"));
720 });
721 }
722
723 #[test]
owned_entry_drop_from_other_threads()724 fn owned_entry_drop_from_other_threads() {
725 run_model("owned_entry_drop_from_other_threads", || {
726 let slab = Arc::new(Slab::<alloc::Track<String>>::new());
727 let key1 = slab
728 .insert(alloc::Track::new(String::from("hello")))
729 .expect("insert item 1");
730 let item1 = slab.clone().get_owned(key1).expect("get key1");
731
732 let slab2 = slab.clone();
733
734 let t1 = thread::spawn(move || {
735 let slab = slab2.clone();
736 let key2 = slab
737 .insert(alloc::Track::new(String::from("goodbye")))
738 .expect("insert item 1");
739 let item2 = slab.clone().get_owned(key2).expect("get key1");
740 let t2 = thread::spawn(move || {
741 assert_eq!(item2.get_ref(), &String::from("goodbye"));
742 test_dbg!(slab2.remove(key1));
743 drop(item2)
744 });
745 assert_eq!(item1.get_ref(), &String::from("hello"));
746 test_dbg!(slab.remove(key2));
747 drop(item1);
748 (t2, key2)
749 });
750
751 let (t2, key2) = t1.join().unwrap();
752 test_dbg!(slab.get(key1));
753 test_dbg!(slab.get(key2));
754
755 t2.join().unwrap();
756
757 assert!(slab.get(key1).is_none());
758 assert!(slab.get(key2).is_none());
759 });
760 }
761