Rollup merge of #126953 - joboet:lazy_key, r=jhpratt · model-checking/verify-rust-std@77a5b51 (original) (raw)

1

``

`` -

//! Implementation of StaticKey for Windows.

``

``

1

`` +

//! Implementation of LazyKey for Windows.

``

2

2

`//!

`

3

3

`//! Windows has no native support for running destructors so we manage our own

`

4

4

`//! list of destructors to keep track of how to destroy keys. We then install a

`

`@@ -13,9 +13,9 @@

`

13

13

`//! don't reach a fixed point after a short while then we just inevitably leak

`

14

14

`//! something.

`

15

15

`//!

`

16

``

`` -

//! The list is implemented as an atomic single-linked list of StaticKeys and

``

``

16

`` +

//! The list is implemented as an atomic single-linked list of LazyKeys and

``

17

17

`//! does not support unregistration. Unfortunately, this means that we cannot

`

18

``

`` -

//! use racy initialization for creating the keys in StaticKey, as that could

``

``

18

`` +

//! use racy initialization for creating the keys in LazyKey, as that could

``

19

19

`//! result in destructors being missed. Hence, we synchronize the creation of

`

20

20

`` //! keys with destructors through INIT_ONCE (std's

``

21

21

`` //! Once cannot be used since it might use TLS itself).

``

`@@ -33,26 +33,26 @@ use crate::sync::atomic::{

`

33

33

`use crate::sys::c;

`

34

34

`use crate::sys::thread_local::guard;

`

35

35

``

36

``

`-

type Key = c::DWORD;

`

``

36

`+

pub type Key = c::DWORD;

`

37

37

`type Dtor = unsafe extern "C" fn(*mut u8);

`

38

38

``

39

``

`-

pub struct StaticKey {

`

``

39

`+

pub struct LazyKey {

`

40

40

`/// The key value shifted up by one. Since TLS_OUT_OF_INDEXES == DWORD::MAX

`

41

41

`/// is not a valid key value, this allows us to use zero as sentinel value

`

42

42

`/// without risking overflow.

`

43

43

`key: AtomicU32,

`

44

44

`dtor: Option,

`

45

``

`-

next: AtomicPtr,

`

``

45

`+

next: AtomicPtr,

`

46

46

`/// Currently, destructors cannot be unregistered, so we cannot use racy

`

47

47

`/// initialization for keys. Instead, we need synchronize initialization.

`

48

48

`` /// Use the Windows-provided Once since it does not require TLS.

``

49

49

`once: UnsafeCell<c::INIT_ONCE>,

`

50

50

`}

`

51

51

``

52

``

`-

impl StaticKey {

`

``

52

`+

impl LazyKey {

`

53

53

`#[inline]

`

54

``

`-

pub const fn new(dtor: Option) -> StaticKey {

`

55

``

`-

StaticKey {

`

``

54

`+

pub const fn new(dtor: Option) -> LazyKey {

`

``

55

`+

LazyKey {

`

56

56

`key: AtomicU32::new(0),

`

57

57

` dtor,

`

58

58

`next: AtomicPtr::new(ptr::null_mut()),

`

`@@ -61,18 +61,7 @@ impl StaticKey {

`

61

61

`}

`

62

62

``

63

63

`#[inline]

`

64

``

`-

pub unsafe fn set(&'static self, val: *mut u8) {

`

65

``

`-

let r = unsafe { c::TlsSetValue(self.key(), val.cast()) };

`

66

``

`-

debug_assert_eq!(r, c::TRUE);

`

67

``

`-

}

`

68

``

-

69

``

`-

#[inline]

`

70

``

`-

pub unsafe fn get(&'static self) -> *mut u8 {

`

71

``

`-

unsafe { c::TlsGetValue(self.key()).cast() }

`

72

``

`-

}

`

73

``

-

74

``

`-

#[inline]

`

75

``

`-

fn key(&'static self) -> Key {

`

``

64

`+

pub fn force(&'static self) -> Key {

`

76

65

`match self.key.load(Acquire) {

`

77

66

`0 => unsafe { self.init() },

`

78

67

` key => key - 1,

`

`@@ -141,17 +130,28 @@ impl StaticKey {

`

141

130

`}

`

142

131

`}

`

143

132

``

144

``

`-

unsafe impl Send for StaticKey {}

`

145

``

`-

unsafe impl Sync for StaticKey {}

`

``

133

`+

unsafe impl Send for LazyKey {}

`

``

134

`+

unsafe impl Sync for LazyKey {}

`

``

135

+

``

136

`+

#[inline]

`

``

137

`+

pub unsafe fn set(key: Key, val: *mut u8) {

`

``

138

`+

let r = unsafe { c::TlsSetValue(key, val.cast()) };

`

``

139

`+

debug_assert_eq!(r, c::TRUE);

`

``

140

`+

}

`

``

141

+

``

142

`+

#[inline]

`

``

143

`+

pub unsafe fn get(key: Key) -> *mut u8 {

`

``

144

`+

unsafe { c::TlsGetValue(key).cast() }

`

``

145

`+

}

`

146

146

``

147

``

`-

static DTORS: AtomicPtr = AtomicPtr::new(ptr::null_mut());

`

``

147

`+

static DTORS: AtomicPtr = AtomicPtr::new(ptr::null_mut());

`

148

148

``

149

149

`/// Should only be called once per key, otherwise loops or breaks may occur in

`

150

150

`/// the linked list.

`

151

``

`-

unsafe fn register_dtor(key: &'static StaticKey) {

`

``

151

`+

unsafe fn register_dtor(key: &'static LazyKey) {

`

152

152

` guard::enable();

`

153

153

``

154

``

`-

let this = <*const StaticKey>::cast_mut(key);

`

``

154

`+

let this = <*const LazyKey>::cast_mut(key);

`

155

155

`// Use acquire ordering to pass along the changes done by the previously

`

156

156

`// registered keys when we store the new head with release ordering.

`

157

157

`let mut head = DTORS.load(Acquire);

`

`@@ -176,9 +176,9 @@ pub unsafe fn run_dtors() {

`

176

176

`let dtor = unsafe { (*cur).dtor.unwrap() };

`

177

177

` cur = unsafe { (*cur).next.load(Relaxed) };

`

178

178

``

179

``

`` -

// In StaticKey::init, we register the dtor before setting key.

``

``

179

`` +

// In LazyKey::init, we register the dtor before setting key.

``

180

180

`` // So if one thread's run_dtors races with another thread executing init on the same

``

181

``

`` -

// StaticKey, we can encounter a key of 0 here. That means this key was never

``

``

181

`` +

// LazyKey, we can encounter a key of 0 here. That means this key was never

``

182

182

`// initialized in this thread so we can safely skip it.

`

183

183

`if pre_key == 0 {

`

184

184

`continue;

`