Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add alloc-tls: custom thread-local variable implementation #85

Merged
merged 1 commit into from
Nov 16, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions alloc-tls/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<!-- Copyright 2017 the authors. See the 'Copyright and license' section of the
README.md file at the top-level directory of this repository.
Licensed under the Apache License, Version 2.0 (the LICENSE-APACHE file) or
the MIT license (the LICENSE-MIT file) at your option. This file may not be
copied, modified, or distributed except according to those terms. -->

# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).

## [Unreleased]
26 changes: 26 additions & 0 deletions alloc-tls/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Copyright 2017 the authors. See the 'Copyright and license' section of the
# README.md file at the top-level directory of this repository.
#
# Licensed under the Apache License, Version 2.0 (the LICENSE-APACHE file) or
# the MIT license (the LICENSE-MIT file) at your option. This file may not be
# copied, modified, or distributed except according to those terms.

[package]
name = "alloc-tls"
version = "0.1.0"
authors = ["Joshua Liebow-Feeser <hello@joshlf.com>"]
license = "Apache-2.0/MIT"
description = "Thread-local storage that is safe for use in implementing global allocators."

keywords = ["thread-local", "allocator", "tls"]
categories = ["memory-management", "os"]

readme = "README.md"
documentation = "https://docs.rs/alloc-tls"
repository = "https://github.com/ezrosent/allocators-rs/tree/master/alloc-tls"

[features]
dylib = []

[dependencies]
alloc-fmt = { path = "../alloc-fmt" }
47 changes: 47 additions & 0 deletions alloc-tls/DESIGN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<!-- Copyright 2017 the authors. See the 'Copyright and license' section of the
README.md file at the top-level directory of this repository.
Licensed under the Apache License, Version 2.0 (the LICENSE-APACHE file) or
the MIT license (the LICENSE-MIT file) at your option. This file may not be
copied, modified, or distributed except according to those terms. -->

Design of alloc-tls
===================

`alloc-tls` provides the `alloc_thread_local!` macro, a near-drop-in replacement
for the standard library's `thread_local!` macro that is safe for use in
implementing a global allocator.

Unlike `thread_local!`, `alloc_thread_local!` address the following issues
unique to implementing a global allocator:
- On platforms that support the `#[thread_local]` attribute, registering
destructors for types that implement `Drop` requires allocation. When a
thread-local is initialized from a call to an allocation function (`malloc`,
`free`, etc), this causes reentrancy. `alloc_thread_local!` can detect this.
- On Mac, it is not safe to access TLS while a dynamic library is being loaded.
When implementing a Mac dynamic library that provides a global allocator,
`alloc_thread_local!` can detect whether the library has been loaded or not,
and can avoid using TLS if `malloc` or other similar calls are made from the
loader itself during loading.

# Reentrancy

Reentrancy is addressed by expanding the number of states that a thread-local
variable can be in. Variables defined using the standard library's
`thread_local!` macro can be in one of three states - Uninitialized, Valid, and
Destroyed. In contrast, variables defined using `alloc_thread_local!` can be in
Uninitialized, Initializing (a new state), Initialized (equivalent to Valid), or
Dropped (equivalent to Destroyed). When a variable is accessed in the
Uninitialized state, it is moved into the Initializing state _before_ any
destructors are registered. This way, if registering destructors causes
allocation, any TLS access in that allocation will find the variable in the
Initializing state, and will thus be able to detect the reentrancy.

# Mac dynamic libraries

On Mac, dynamic libraries can specify library constructors - functions that are
called immediately after the library is loaded. When compiling a dynamic library
for Mac, `alloc-tls` defines a global `DYLD_LOADED` variable that is initialized
to false. A constructor is registered that sets it to true. When a TLS variable
is accessed, if `DYLD_LOADED` is false, the access fails, leaving it up to the
caller to use some slow path that doesn't rely on thread-local values.
29 changes: 29 additions & 0 deletions alloc-tls/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<!-- Copyright 2017 the authors. See the 'Copyright and license' section of the
README.md file at the top-level directory of this repository.
Licensed under the Apache License, Version 2.0 (the LICENSE-APACHE file) or
the MIT license (the LICENSE-MIT file) at your option. This file may not be
copied, modified, or distributed except according to those terms. -->

alloc-tls
=========

`alloc-tls` provides the `alloc_thread_local!` macro, a near-drop-in replacement
for the standard library's `thread_local!` macro that is safe for use in
implementing a global allocator.

Unlike `thread_local!`, `alloc_thread_local!` address the following issues
unique to implementing a global allocator:
- On platforms that support the `#[thread_local]` attribute, registering
destructors for types that implement `Drop` requires allocation. When a
thread-local is initialized from a call to an allocation function (`malloc`,
`free`, etc), this causes reentrancy. `alloc_thread_local!` can detect this.
- On Mac, it is not safe to access TLS while a dynamic library is being loaded.
When implementing a Mac dynamic library that provides a global allocator,
`alloc_thread_local!` can detect whether the library has been loaded or not,
and can avoid using TLS if `malloc` or other similar calls are made from the
loader itself during loading.

Known limitations:
- `alloc-tls` does not currently support platforms that do not support the
`#[thread_local]` attribute.
Loading