+impl<'mir, 'tcx: 'mir> EvalContextPrivExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
+trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
+ /// Schedule TLS destructors for the main thread on Windows. The
+ /// implementation assumes that we do not support concurrency on Windows
+ /// yet.
+ fn schedule_windows_tls_dtors(&mut self) -> InterpResult<'tcx> {
+ let this = self.eval_context_mut();
+ let active_thread = this.get_active_thread();
+ assert_eq!(this.get_total_thread_count(), 1, "concurrency on Windows is not supported");
+ // Windows has a special magic linker section that is run on certain events.
+ // Instead of searching for that section and supporting arbitrary hooks in there
+ // (that would be basically https://github.com/rust-lang/miri/issues/450),
+ // we specifically look up the static in libstd that we know is placed
+ // in that section.
+ let thread_callback = this.eval_path_scalar(&["std", "sys", "windows", "thread_local_key", "p_thread_callback"])?;
+ let thread_callback = this.memory.get_fn(thread_callback.check_init()?)?.as_instance()?;
+
+ // The signature of this function is `unsafe extern "system" fn(h: c::LPVOID, dwReason: c::DWORD, pv: c::LPVOID)`.
+ let reason = this.eval_path_scalar(&["std", "sys", "windows", "c", "DLL_THREAD_DETACH"])?;
+ let ret_place = MPlaceTy::dangling(this.machine.layouts.unit, this).into();
+ this.call_function(
+ thread_callback,
+ Abi::System { unwind: false },
+ &[Scalar::null_ptr(this).into(), reason.into(), Scalar::null_ptr(this).into()],
+ Some(&ret_place),
+ StackPopCleanup::None { cleanup: true },
+ )?;
+
+ this.enable_thread(active_thread);
+ Ok(())
+ }
+
+ /// Schedule the MacOS thread destructor of the thread local storage to be
+ /// executed. Returns `true` if scheduled.
+ ///
+ /// Note: It is safe to call this function also on other Unixes.
+ fn schedule_macos_tls_dtor(&mut self) -> InterpResult<'tcx, bool> {
+ let this = self.eval_context_mut();
+ let thread_id = this.get_active_thread();
+ if let Some((instance, data)) = this.machine.tls.macos_thread_dtors.remove(&thread_id) {
+ trace!("Running macos dtor {:?} on {:?} at {:?}", instance, data, thread_id);
+
+ let ret_place = MPlaceTy::dangling(this.machine.layouts.unit, this).into();
+ this.call_function(
+ instance,
+ Abi::C { unwind: false },
+ &[data.into()],
+ Some(&ret_place),
+ StackPopCleanup::None { cleanup: true },
+ )?;
+
+ // Enable the thread so that it steps through the destructor which
+ // we just scheduled. Since we deleted the destructor, it is
+ // guaranteed that we will schedule it again. The `dtors_running`
+ // flag will prevent the code from adding the destructor again.
+ this.enable_thread(thread_id);
+ Ok(true)
+ } else {
+ Ok(false)
+ }
+ }
+
+ /// Schedule a pthread TLS destructor. Returns `true` if found
+ /// a destructor to schedule, and `false` otherwise.
+ fn schedule_next_pthread_tls_dtor(&mut self) -> InterpResult<'tcx, bool> {