1use std::any::Any;
2use std::cell::RefCell;
3use std::collections::VecDeque;
4use std::collections::hash_map::Entry;
5use std::default::Default;
6use std::ops::Not;
7use std::rc::Rc;
8use std::{fmt, iter};
9
10use rustc_abi::Size;
11use rustc_data_structures::fx::FxHashMap;
12
13use super::vector_clock::VClock;
14use crate::*;
15
16#[derive(Copy, Clone, Hash, PartialEq, Eq, Debug)]
18pub enum AccessKind {
19 Read,
20 Write,
21 Dealloc,
22}
23
24impl fmt::Display for AccessKind {
25 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
26 match self {
27 AccessKind::Read => write!(f, "read"),
28 AccessKind::Write => write!(f, "write"),
29 AccessKind::Dealloc => write!(f, "deallocation"),
30 }
31 }
32}
33
34pub trait SyncObj: Any {
36 fn on_access<'tcx>(&self, _access_kind: AccessKind) -> InterpResult<'tcx> {
38 interp_ok(())
39 }
40
41 fn delete_on_write(&self) -> bool {
44 false
45 }
46}
47
48impl dyn SyncObj {
49 #[inline(always)]
50 pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
51 let x: &dyn Any = self;
52 x.downcast_ref()
53 }
54}
55
56impl fmt::Debug for dyn SyncObj {
57 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
58 f.debug_struct("SyncObj").finish_non_exhaustive()
59 }
60}
61
62#[derive(Default, Debug)]
64struct Mutex {
65 owner: Option<ThreadId>,
67 lock_count: usize,
69 queue: VecDeque<ThreadId>,
71 clock: VClock,
73}
74
75#[derive(Default, Clone, Debug)]
76pub struct MutexRef(Rc<RefCell<Mutex>>);
77
78impl MutexRef {
79 pub fn new() -> Self {
80 Self(Default::default())
81 }
82
83 pub fn owner(&self) -> Option<ThreadId> {
85 self.0.borrow().owner
86 }
87
88 pub fn queue_is_empty(&self) -> bool {
89 self.0.borrow().queue.is_empty()
90 }
91}
92
93impl VisitProvenance for MutexRef {
94 fn visit_provenance(&self, _visit: &mut VisitWith<'_>) {}
96}
97
98#[derive(Default, Debug)]
100struct RwLock {
101 writer: Option<ThreadId>,
103 readers: FxHashMap<ThreadId, usize>,
106 writer_queue: VecDeque<ThreadId>,
108 reader_queue: VecDeque<ThreadId>,
110 clock_unlocked: VClock,
119 clock_current_readers: VClock,
130}
131
132impl RwLock {
133 #[inline]
134 fn is_locked(&self) -> bool {
136 trace!(
137 "rwlock_is_locked: writer is {:?} and there are {} reader threads (some of which could hold multiple read locks)",
138 self.writer,
139 self.readers.len(),
140 );
141 self.writer.is_some() || self.readers.is_empty().not()
142 }
143
144 #[inline]
146 fn is_write_locked(&self) -> bool {
147 trace!("rwlock_is_write_locked: writer is {:?}", self.writer);
148 self.writer.is_some()
149 }
150}
151
152#[derive(Default, Clone, Debug)]
153pub struct RwLockRef(Rc<RefCell<RwLock>>);
154
155impl RwLockRef {
156 pub fn new() -> Self {
157 Self(Default::default())
158 }
159
160 pub fn is_locked(&self) -> bool {
161 self.0.borrow().is_locked()
162 }
163
164 pub fn is_write_locked(&self) -> bool {
165 self.0.borrow().is_write_locked()
166 }
167
168 pub fn queue_is_empty(&self) -> bool {
169 let inner = self.0.borrow();
170 inner.reader_queue.is_empty() && inner.writer_queue.is_empty()
171 }
172}
173
174impl VisitProvenance for RwLockRef {
175 fn visit_provenance(&self, _visit: &mut VisitWith<'_>) {}
177}
178
179#[derive(Default, Debug)]
181struct Condvar {
182 waiters: VecDeque<ThreadId>,
183 clock: VClock,
189}
190
191#[derive(Default, Clone, Debug)]
192pub struct CondvarRef(Rc<RefCell<Condvar>>);
193
194impl CondvarRef {
195 pub fn new() -> Self {
196 Self(Default::default())
197 }
198
199 pub fn queue_is_empty(&self) -> bool {
200 self.0.borrow().waiters.is_empty()
201 }
202}
203
204impl VisitProvenance for CondvarRef {
205 fn visit_provenance(&self, _visit: &mut VisitWith<'_>) {}
207}
208
209#[derive(Default, Debug)]
211struct Semaphore {
212 waiters: VecDeque<ThreadId>,
213 value: u64,
214 clock: VClock,
216}
217
218#[derive(Default, Clone, Debug)]
219pub struct SemaphoreRef(Rc<RefCell<Semaphore>>);
220
221impl SemaphoreRef {
222 pub fn new(value: u64) -> Self {
223 Self(Rc::new(RefCell::new(Semaphore { value, ..Default::default() })))
224 }
225
226 pub fn value(&self) -> u64 {
227 self.0.borrow().value
228 }
229
230 pub fn queue_is_empty(&self) -> bool {
231 self.0.borrow().waiters.is_empty()
232 }
233}
234
235impl VisitProvenance for SemaphoreRef {
236 fn visit_provenance(&self, _visit: &mut VisitWith<'_>) {}
238}
239
240#[derive(Default, Debug)]
242struct Futex {
243 waiters: Vec<FutexWaiter>,
244 clock: VClock,
250}
251
252#[derive(Default, Clone, Debug)]
253pub struct FutexRef(Rc<RefCell<Futex>>);
254
255impl FutexRef {
256 pub fn new() -> Self {
257 Self(Default::default())
258 }
259
260 pub fn waiters(&self) -> usize {
261 self.0.borrow().waiters.len()
262 }
263}
264
265impl VisitProvenance for FutexRef {
266 fn visit_provenance(&self, _visit: &mut VisitWith<'_>) {}
268}
269
270#[derive(Debug)]
272struct FutexWaiter {
273 thread: ThreadId,
275 bitset: u32,
277}
278
279impl<'tcx> EvalContextExtPriv<'tcx> for crate::MiriInterpCx<'tcx> {}
281pub(super) trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
282 fn condvar_reacquire_mutex(
283 &mut self,
284 mutex_ref: MutexRef,
285 retval: Scalar,
286 dest: MPlaceTy<'tcx>,
287 ) -> InterpResult<'tcx> {
288 let this = self.eval_context_mut();
289 if let Some(owner) = mutex_ref.owner() {
290 assert_ne!(owner, this.active_thread());
291 this.mutex_enqueue_and_block(mutex_ref, Some((retval, dest)));
292 } else {
293 this.mutex_lock(&mutex_ref)?;
295 this.write_scalar(retval, &dest)?;
297 }
298 interp_ok(())
299 }
300}
301
302impl<'tcx> AllocExtra<'tcx> {
303 fn get_sync<T: 'static>(&self, offset: Size) -> Option<&T> {
304 self.sync_objs.get(&offset).and_then(|s| s.downcast_ref::<T>())
305 }
306}
307
308impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
313pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
314 fn get_sync_or_init<'a, T: SyncObj>(
319 &'a mut self,
320 ptr: Pointer,
321 new: impl FnOnce(&'a mut MiriMachine<'tcx>) -> T,
322 ) -> Option<&'a T>
323 where
324 'tcx: 'a,
325 {
326 let this = self.eval_context_mut();
327 if !this.ptr_try_get_alloc_id(ptr, 0).ok().is_some_and(|(alloc_id, offset, ..)| {
328 let info = this.get_alloc_info(alloc_id);
329 info.kind == AllocKind::LiveData && info.mutbl.is_mut() && offset < info.size
330 }) {
331 return None;
332 }
333 let (alloc, offset, _) = this.ptr_get_alloc_id(ptr, 0).unwrap();
335 let (alloc_extra, machine) = this.get_alloc_extra_mut(alloc).unwrap();
336 if alloc_extra.get_sync::<T>(offset).is_none() {
338 let new = new(machine);
339 alloc_extra.sync_objs.insert(offset, Box::new(new));
340 }
341 Some(alloc_extra.get_sync::<T>(offset).unwrap())
342 }
343
344 fn get_immovable_sync_with_static_init<'a, T: SyncObj>(
361 &'a mut self,
362 obj: &MPlaceTy<'tcx>,
363 init_offset: Size,
364 uninit_val: u8,
365 init_val: u8,
366 new_meta_obj: impl FnOnce(&mut MiriInterpCx<'tcx>) -> InterpResult<'tcx, T>,
367 ) -> InterpResult<'tcx, &'a T>
368 where
369 'tcx: 'a,
370 {
371 assert!(init_val != uninit_val);
372 let this = self.eval_context_mut();
373 this.check_ptr_access(
374 obj.ptr(),
375 obj.layout.size,
376 CheckInAllocMsg::Dereferenceable("pointer"),
377 )?;
378 assert!(init_offset < obj.layout.size); let init_field = obj.offset(init_offset, this.machine.layouts.u8, this)?;
380
381 let (alloc, offset, _) = this.ptr_get_alloc_id(init_field.ptr(), 0)?;
382 let (alloc_extra, _machine) = this.get_alloc_extra_mut(alloc)?;
383 if alloc_extra.get_sync::<T>(offset).is_some() {
385 let (alloc_extra, _machine) = this.get_alloc_extra_mut(alloc).unwrap();
386 return interp_ok(alloc_extra.get_sync::<T>(offset).unwrap());
387 }
388
389 let meta_obj = new_meta_obj(this)?;
391 let (old_init, success) = this.atomic_compare_exchange(
392 &init_field,
393 &ImmTy::from_scalar(Scalar::from_u8(uninit_val), this.machine.layouts.u8),
394 Scalar::from_u8(init_val),
395 AtomicRwOrd::Relaxed,
396 AtomicReadOrd::Relaxed,
397 false,
398 )?;
399 if !success {
400 assert_eq!(
402 old_init.to_u8()?,
403 init_val,
404 "`new_meta_obj` should have ensured that this CAS succeeds"
405 );
406 }
407
408 let (alloc_extra, _machine) = this.get_alloc_extra_mut(alloc).unwrap();
409 assert!(meta_obj.delete_on_write());
410 alloc_extra.sync_objs.insert(offset, Box::new(meta_obj));
411 interp_ok(alloc_extra.get_sync::<T>(offset).unwrap())
412 }
413
414 fn init_immovable_sync<'a, T: SyncObj>(
417 &'a mut self,
418 obj: &MPlaceTy<'tcx>,
419 init_offset: Size,
420 init_val: u8,
421 new_meta_obj: T,
422 ) -> InterpResult<'tcx, Option<&'a T>>
423 where
424 'tcx: 'a,
425 {
426 let this = self.eval_context_mut();
427 this.check_ptr_access(
428 obj.ptr(),
429 obj.layout.size,
430 CheckInAllocMsg::Dereferenceable("pointer"),
431 )?;
432 assert!(init_offset < obj.layout.size); let init_field = obj.offset(init_offset, this.machine.layouts.u8, this)?;
434
435 this.write_bytes_ptr(obj.ptr(), iter::repeat_n(0, obj.layout.size.bytes_usize()))?;
437 this.write_scalar(Scalar::from_u8(init_val), &init_field)?;
438
439 let (alloc, offset, _) = this.ptr_get_alloc_id(init_field.ptr(), 0)?;
441 let (alloc_extra, _machine) = this.get_alloc_extra_mut(alloc).unwrap();
442 assert!(new_meta_obj.delete_on_write());
443 alloc_extra.sync_objs.insert(offset, Box::new(new_meta_obj));
444 interp_ok(Some(alloc_extra.get_sync::<T>(offset).unwrap()))
445 }
446
447 fn mutex_lock(&mut self, mutex_ref: &MutexRef) -> InterpResult<'tcx> {
449 let this = self.eval_context_mut();
450 let thread = this.active_thread();
451 let mut mutex = mutex_ref.0.borrow_mut();
452 if let Some(current_owner) = mutex.owner {
453 assert_eq!(thread, current_owner, "mutex already locked by another thread");
454 assert!(
455 mutex.lock_count > 0,
456 "invariant violation: lock_count == 0 iff the thread is unlocked"
457 );
458 } else {
459 mutex.owner = Some(thread);
460 }
461 mutex.lock_count = mutex.lock_count.strict_add(1);
462 this.acquire_clock(&mutex.clock)?;
463 interp_ok(())
464 }
465
466 fn mutex_unlock(&mut self, mutex_ref: &MutexRef) -> InterpResult<'tcx, Option<usize>> {
471 let this = self.eval_context_mut();
472 let mut mutex = mutex_ref.0.borrow_mut();
473 interp_ok(if let Some(current_owner) = mutex.owner {
474 if current_owner != this.machine.threads.active_thread() {
476 return interp_ok(None);
478 }
479 let old_lock_count = mutex.lock_count;
480 mutex.lock_count = old_lock_count.strict_sub(1);
481 if mutex.lock_count == 0 {
482 mutex.owner = None;
483 this.release_clock(|clock| mutex.clock.clone_from(clock))?;
487 let thread_id = mutex.queue.pop_front();
488 drop(mutex);
491 if let Some(thread_id) = thread_id {
492 this.unblock_thread(thread_id, BlockReason::Mutex)?;
493 }
494 }
495 Some(old_lock_count)
496 } else {
497 None
499 })
500 }
501
502 #[inline]
507 fn mutex_enqueue_and_block(
508 &mut self,
509 mutex_ref: MutexRef,
510 retval_dest: Option<(Scalar, MPlaceTy<'tcx>)>,
511 ) {
512 let this = self.eval_context_mut();
513 let thread = this.active_thread();
514 let mut mutex = mutex_ref.0.borrow_mut();
515 mutex.queue.push_back(thread);
516 assert!(mutex.owner.is_some(), "queuing on unlocked mutex");
517 drop(mutex);
518 this.block_thread(
519 BlockReason::Mutex,
520 None,
521 callback!(
522 @capture<'tcx> {
523 mutex_ref: MutexRef,
524 retval_dest: Option<(Scalar, MPlaceTy<'tcx>)>,
525 }
526 |this, unblock: UnblockKind| {
527 assert_eq!(unblock, UnblockKind::Ready);
528
529 assert!(mutex_ref.owner().is_none());
530 this.mutex_lock(&mutex_ref)?;
531
532 if let Some((retval, dest)) = retval_dest {
533 this.write_scalar(retval, &dest)?;
534 }
535
536 interp_ok(())
537 }
538 ),
539 );
540 }
541
542 fn rwlock_reader_lock(&mut self, rwlock_ref: &RwLockRef) -> InterpResult<'tcx> {
545 let this = self.eval_context_mut();
546 let thread = this.active_thread();
547 trace!("rwlock_reader_lock: now also held (one more time) by {:?}", thread);
548 let mut rwlock = rwlock_ref.0.borrow_mut();
549 assert!(!rwlock.is_write_locked(), "the lock is write locked");
550 let count = rwlock.readers.entry(thread).or_insert(0);
551 *count = count.strict_add(1);
552 this.acquire_clock(&rwlock.clock_unlocked)?;
553 interp_ok(())
554 }
555
556 fn rwlock_reader_unlock(&mut self, rwlock_ref: &RwLockRef) -> InterpResult<'tcx, bool> {
559 let this = self.eval_context_mut();
560 let thread = this.active_thread();
561 let mut rwlock = rwlock_ref.0.borrow_mut();
562 match rwlock.readers.entry(thread) {
563 Entry::Occupied(mut entry) => {
564 let count = entry.get_mut();
565 assert!(*count > 0, "rwlock locked with count == 0");
566 *count -= 1;
567 if *count == 0 {
568 trace!("rwlock_reader_unlock: no longer held by {:?}", thread);
569 entry.remove();
570 } else {
571 trace!("rwlock_reader_unlock: held one less time by {:?}", thread);
572 }
573 }
574 Entry::Vacant(_) => return interp_ok(false), }
576 this.release_clock(|clock| rwlock.clock_current_readers.join(clock))?;
578
579 if rwlock.is_locked().not() {
581 let rwlock_ref = &mut *rwlock;
585 rwlock_ref.clock_unlocked.clone_from(&rwlock_ref.clock_current_readers);
586 if let Some(writer) = rwlock_ref.writer_queue.pop_front() {
588 drop(rwlock); this.unblock_thread(writer, BlockReason::RwLock)?;
590 }
591 }
592 interp_ok(true)
593 }
594
595 #[inline]
598 fn rwlock_enqueue_and_block_reader(
599 &mut self,
600 rwlock_ref: RwLockRef,
601 retval: Scalar,
602 dest: MPlaceTy<'tcx>,
603 ) {
604 let this = self.eval_context_mut();
605 let thread = this.active_thread();
606 let mut rwlock = rwlock_ref.0.borrow_mut();
607 rwlock.reader_queue.push_back(thread);
608 assert!(rwlock.is_write_locked(), "read-queueing on not write locked rwlock");
609 drop(rwlock);
610 this.block_thread(
611 BlockReason::RwLock,
612 None,
613 callback!(
614 @capture<'tcx> {
615 rwlock_ref: RwLockRef,
616 retval: Scalar,
617 dest: MPlaceTy<'tcx>,
618 }
619 |this, unblock: UnblockKind| {
620 assert_eq!(unblock, UnblockKind::Ready);
621 this.rwlock_reader_lock(&rwlock_ref)?;
622 this.write_scalar(retval, &dest)?;
623 interp_ok(())
624 }
625 ),
626 );
627 }
628
629 #[inline]
631 fn rwlock_writer_lock(&mut self, rwlock_ref: &RwLockRef) -> InterpResult<'tcx> {
632 let this = self.eval_context_mut();
633 let thread = this.active_thread();
634 trace!("rwlock_writer_lock: now held by {:?}", thread);
635
636 let mut rwlock = rwlock_ref.0.borrow_mut();
637 assert!(!rwlock.is_locked(), "the rwlock is already locked");
638 rwlock.writer = Some(thread);
639 this.acquire_clock(&rwlock.clock_unlocked)?;
640 interp_ok(())
641 }
642
643 #[inline]
646 fn rwlock_writer_unlock(&mut self, rwlock_ref: &RwLockRef) -> InterpResult<'tcx, bool> {
647 let this = self.eval_context_mut();
648 let thread = this.active_thread();
649 let mut rwlock = rwlock_ref.0.borrow_mut();
650 interp_ok(if let Some(current_writer) = rwlock.writer {
651 if current_writer != thread {
652 return interp_ok(false);
654 }
655 rwlock.writer = None;
656 trace!("rwlock_writer_unlock: unlocked by {:?}", thread);
657 this.release_clock(|clock| rwlock.clock_unlocked.clone_from(clock))?;
659
660 if let Some(writer) = rwlock.writer_queue.pop_front() {
666 drop(rwlock); this.unblock_thread(writer, BlockReason::RwLock)?;
668 } else {
669 let readers = std::mem::take(&mut rwlock.reader_queue);
671 drop(rwlock); for reader in readers {
673 this.unblock_thread(reader, BlockReason::RwLock)?;
674 }
675 }
676 true
677 } else {
678 false
679 })
680 }
681
682 #[inline]
685 fn rwlock_enqueue_and_block_writer(
686 &mut self,
687 rwlock_ref: RwLockRef,
688 retval: Scalar,
689 dest: MPlaceTy<'tcx>,
690 ) {
691 let this = self.eval_context_mut();
692 let thread = this.active_thread();
693 let mut rwlock = rwlock_ref.0.borrow_mut();
694 rwlock.writer_queue.push_back(thread);
695 assert!(rwlock.is_locked(), "write-queueing on unlocked rwlock");
696 drop(rwlock);
697 this.block_thread(
698 BlockReason::RwLock,
699 None,
700 callback!(
701 @capture<'tcx> {
702 rwlock_ref: RwLockRef,
703 retval: Scalar,
704 dest: MPlaceTy<'tcx>,
705 }
706 |this, unblock: UnblockKind| {
707 assert_eq!(unblock, UnblockKind::Ready);
708 this.rwlock_writer_lock(&rwlock_ref)?;
709 this.write_scalar(retval, &dest)?;
710 interp_ok(())
711 }
712 ),
713 );
714 }
715
716 fn condvar_wait(
720 &mut self,
721 condvar_ref: CondvarRef,
722 mutex_ref: MutexRef,
723 deadline: Option<Deadline>,
724 retval_succ: Scalar,
725 retval_timeout: Scalar,
726 dest: MPlaceTy<'tcx>,
727 ) -> InterpResult<'tcx> {
728 let this = self.eval_context_mut();
729 if let Some(old_locked_count) = this.mutex_unlock(&mutex_ref)? {
730 if old_locked_count != 1 {
731 throw_unsup_format!(
732 "awaiting a condvar on a mutex acquired multiple times is not supported"
733 );
734 }
735 } else {
736 throw_ub_format!(
737 "awaiting a condvar on a mutex that is unlocked or owned by a different thread"
738 );
739 }
740 let thread = this.active_thread();
741
742 condvar_ref.0.borrow_mut().waiters.push_back(thread);
743 this.block_thread(
744 BlockReason::Condvar,
745 deadline,
746 callback!(
747 @capture<'tcx> {
748 condvar_ref: CondvarRef,
749 mutex_ref: MutexRef,
750 retval_succ: Scalar,
751 retval_timeout: Scalar,
752 dest: MPlaceTy<'tcx>,
753 }
754 |this, unblock: UnblockKind| {
755 match unblock {
756 UnblockKind::Ready => {
757 this.acquire_clock(
759 &condvar_ref.0.borrow().clock,
760 )?;
761 this.condvar_reacquire_mutex(mutex_ref, retval_succ, dest)
764 }
765 UnblockKind::TimedOut => {
766 let thread = this.active_thread();
768 let waiters = &mut condvar_ref.0.borrow_mut().waiters;
769 waiters.retain(|waiter| *waiter != thread);
770 this.condvar_reacquire_mutex(mutex_ref, retval_timeout, dest)
772 }
773 }
774 }
775 ),
776 );
777 interp_ok(())
778 }
779
780 fn condvar_signal(&mut self, condvar_ref: &CondvarRef) -> InterpResult<'tcx, bool> {
783 let this = self.eval_context_mut();
784 let mut condvar = condvar_ref.0.borrow_mut();
785
786 this.release_clock(|clock| condvar.clock.clone_from(clock))?;
788 let Some(waiter) = condvar.waiters.pop_front() else {
789 return interp_ok(false);
790 };
791 drop(condvar);
792 this.unblock_thread(waiter, BlockReason::Condvar)?;
793 interp_ok(true)
794 }
795
796 fn futex_wait(
799 &mut self,
800 futex_ref: FutexRef,
801 bitset: u32,
802 deadline: Option<Deadline>,
803 callback: DynUnblockCallback<'tcx>,
804 ) {
805 let this = self.eval_context_mut();
806 let thread = this.active_thread();
807 let mut futex = futex_ref.0.borrow_mut();
808 let waiters = &mut futex.waiters;
809 assert!(waiters.iter().all(|waiter| waiter.thread != thread), "thread is already waiting");
810 waiters.push(FutexWaiter { thread, bitset });
811 drop(futex);
812
813 this.block_thread(
814 BlockReason::Futex,
815 deadline,
816 callback!(
817 @capture<'tcx> {
818 futex_ref: FutexRef,
819 callback: DynUnblockCallback<'tcx>,
820 }
821 |this, unblock: UnblockKind| {
822 match unblock {
823 UnblockKind::Ready => {
824 let futex = futex_ref.0.borrow();
825 this.acquire_clock(&futex.clock)?;
827 },
828 UnblockKind::TimedOut => {
829 let thread = this.active_thread();
831 let mut futex = futex_ref.0.borrow_mut();
832 futex.waiters.retain(|waiter| waiter.thread != thread);
833 },
834 }
835
836 callback.call(this, unblock)
837 }
838 ),
839 );
840 }
841
842 fn futex_wake(
845 &mut self,
846 futex_ref: &FutexRef,
847 bitset: u32,
848 count: usize,
849 ) -> InterpResult<'tcx, usize> {
850 let this = self.eval_context_mut();
851 let mut futex = futex_ref.0.borrow_mut();
852
853 this.release_clock(|clock| futex.clock.clone_from(clock))?;
855
856 let wake_threads: Vec<_> =
860 futex.waiters.extract_if(.., |w| w.bitset & bitset != 0).take(count).collect();
861 drop(futex);
862
863 let woken = wake_threads.len();
864 for waiter in wake_threads {
865 this.unblock_thread(waiter.thread, BlockReason::Futex)?;
866 }
867
868 interp_ok(woken)
869 }
870
871 fn semaphore_decrement(
877 &mut self,
878 semaphore_ref: SemaphoreRef,
879 deadline: Option<Deadline>,
880 callback: DynUnblockCallback<'tcx>,
881 ) -> InterpResult<'tcx> {
882 let this = self.eval_context_mut();
883
884 let mut semaphore = semaphore_ref.0.borrow_mut();
885 if let Some(new_value) = semaphore.value.checked_sub(1) {
886 semaphore.value = new_value;
887 this.acquire_clock(&semaphore.clock)?;
888 drop(semaphore);
889 return callback.call(this, UnblockKind::Ready);
890 }
891
892 semaphore.waiters.push_back(this.active_thread());
894 drop(semaphore);
895
896 this.block_thread(
897 BlockReason::Semaphore,
898 deadline.clone(),
899 callback!(
900 @capture<'tcx> {
901 semaphore_ref: SemaphoreRef,
902 deadline: Option<Deadline>,
903 callback: DynUnblockCallback<'tcx>,
904 }
905 |this, unblock: UnblockKind| {
906 match unblock {
907 UnblockKind::TimedOut => {
908 let thread = this.active_thread();
910 let mut semaphore = semaphore_ref.0.borrow_mut();
911 semaphore.waiters.retain(|&waiter| waiter != thread);
912 return callback.call(this, UnblockKind::TimedOut);
914 }
915 UnblockKind::Ready => {
916 this.semaphore_decrement(semaphore_ref, deadline, callback)
919 }
920 }
921 }
922 ),
923 );
924 interp_ok(())
925 }
926
927 fn semaphore_increment(&mut self, semaphore_ref: &SemaphoreRef) -> InterpResult<'tcx, bool> {
930 let this = self.eval_context_mut();
931
932 let mut semaphore = semaphore_ref.0.borrow_mut();
933 let wake_thread =
935 (semaphore.value == 0).then_some(()).and_then(|()| semaphore.waiters.pop_front());
936 let Some(new_value) = semaphore.value.checked_add(1) else {
938 throw_unsup_format!("the counter of a semaphore overflowed")
939 };
940 semaphore.value = new_value;
941 this.release_clock(|clock| semaphore.clock.clone_from(clock))?;
943 drop(semaphore);
944
945 if let Some(thread) = wake_thread {
946 this.unblock_thread(thread, BlockReason::Semaphore)?;
947 }
948
949 interp_ok(wake_thread.is_some())
950 }
951}