Skip to content

Comments

parallel: add support to explicitly destroy TLS keys#98

Open
compnerd wants to merge 1 commit intosaeta:mainfrom
compnerd:deleted
Open

parallel: add support to explicitly destroy TLS keys#98
compnerd wants to merge 1 commit intosaeta:mainfrom
compnerd:deleted

Conversation

@compnerd
Copy link
Collaborator

In most modern pthread implementations, the TLS key does not create heap
allocations. However, this is not true for all implementations of TLS.
Extend the interface to permit the destruction of the key to release
resources.

Also add an implementation which conforms to the POSIX threading
interfaces.

Extend the change a bit further to allow for the resetting of the key
itself to a TLS implementation specific invalid value. Although this
unconstifies the value, it will make it easier to identify invalid uses
of the key (e.g. use-after-free).

In most modern pthread implementations, the TLS key does not create heap
allocations.  However, this is not true for all implementations of TLS.
Extend the interface to permit the destruction of the key to release
resources.

Also add an implementation which conforms to the POSIX threading
interfaces.

Extend the change a bit further to allow for the resetting of the key
itself to a TLS implementation specific invalid value.  Although this
unconstifies the value, it will make it easier to identify invalid uses
of the key (e.g. use-after-free).
Copy link
Owner

@saeta saeta left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you very much @compnerd for this! I had a thought for a slightly more ergonomic design; am I missing something that would prevent this design?

/// Makes a new key; the returned key should be used for the entire process lifetime.
static func makeKey() -> Key
/// Invalidates a previously constructed key, freeing resources
static func destroyKey(_ key: inout Key)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would a better design be for the Key's destructor to handle cleanup?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The destroyKey is different from the key destructor - it frees the TLS slot for re-use, it does not handle the cleanup of the TLS key itself, which remains the duty of the TLS destructor.

/// Token used to index into the thread local storage.
public struct Key<Value: AnyObject> {
fileprivate let key: Underlying.Key
fileprivate var key: Underlying.Key
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: if Underlying.Key is a class, then I think this change can be reverted. WDYT?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can revert this change even without that - I call that out in the commit message with an explanation of why I changed this. It's purely for detection purposes. If we say that the user is responsible for knowing when they have invalidated the TLS slot, this can remain a let binding. One could argue that the destroy is an explicit action - most usage will be for the lifetime of the program, in which case, you just leak the slot which is irrelevant because the application is terminating and the resources will be released as a byproduct. But, if you want to change the underlying Key to class even outside of that reasoning, I can certainly do that.

Key(key: Underlying.makeKey())
}

/// Deallocates a key for type `T`.
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto.

#if os(Windows)
fatalError("Unimplemented!")
#else
pthread_key_delete(key.value)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's change Key to a class, and move this into deinit. WDYT?

@texasmichelle texasmichelle changed the base branch from master to main December 8, 2020 01:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants