diff options
| author | Alex Crichton <alex@alexcrichton.com> | 2017-06-03 14:54:08 -0700 |
|---|---|---|
| committer | Alex Crichton <alex@alexcrichton.com> | 2017-07-05 14:37:01 -0700 |
| commit | 695dee063bcd40f154bb27b7beafcb3d4dd775ac (patch) | |
| tree | 8ac64f40091434e679b4221343dce7447c4f1236 /src/doc | |
| parent | 4c225c4d1732537aff63dd97c2b7ac681fd3d188 (diff) | |
| download | rust-695dee063bcd40f154bb27b7beafcb3d4dd775ac.tar.gz rust-695dee063bcd40f154bb27b7beafcb3d4dd775ac.zip | |
rustc: Implement the #[global_allocator] attribute
This PR is an implementation of [RFC 1974] which specifies a new method of defining a global allocator for a program. This obsoletes the old `#![allocator]` attribute and also removes support for it. [RFC 1974]: https://github.com/rust-lang/rfcs/pull/197 The new `#[global_allocator]` attribute solves many issues encountered with the `#![allocator]` attribute such as composition and restrictions on the crate graph itself. The compiler now has much more control over the ABI of the allocator and how it's implemented, allowing much more freedom in terms of how this feature is implemented. cc #27389
Diffstat (limited to 'src/doc')
3 files changed, 78 insertions, 119 deletions
diff --git a/src/doc/unstable-book/src/language-features/allocator-internals.md b/src/doc/unstable-book/src/language-features/allocator-internals.md new file mode 100644 index 00000000000..2023d758fe3 --- /dev/null +++ b/src/doc/unstable-book/src/language-features/allocator-internals.md @@ -0,0 +1,7 @@ +# `allocator_internals` + +This feature does not have a tracking issue, it is an unstable implementation +detail of the `global_allocator` feature not intended for use outside the +compiler. + +------------------------ diff --git a/src/doc/unstable-book/src/language-features/allocator.md b/src/doc/unstable-book/src/language-features/allocator.md deleted file mode 100644 index cfcf8e22d70..00000000000 --- a/src/doc/unstable-book/src/language-features/allocator.md +++ /dev/null @@ -1,119 +0,0 @@ -# `allocator` - -The tracking issue for this feature is: [#27389] - -[#27389]: https://github.com/rust-lang/rust/issues/27389 - ------------------------- - -Sometimes even the choices of jemalloc vs the system allocator aren't enough and -an entirely new custom allocator is required. In this you'll write your own -crate which implements the allocator API (e.g. the same as `alloc_system` or -`alloc_jemalloc`). As an example, let's take a look at a simplified and -annotated version of `alloc_system` - -```rust,no_run -# // Only needed for rustdoc --test down below. -# #![feature(lang_items)] -// The compiler needs to be instructed that this crate is an allocator in order -// to realize that when this is linked in another allocator like jemalloc should -// not be linked in. -#![feature(allocator)] -#![allocator] - -// Allocators are not allowed to depend on the standard library which in turn -// requires an allocator in order to avoid circular dependencies. This crate, -// however, can use all of libcore. -#![no_std] - -// Let's give a unique name to our custom allocator: -#![crate_name = "my_allocator"] -#![crate_type = "rlib"] - -// Our system allocator will use the in-tree libc crate for FFI bindings. Note -// that currently the external (crates.io) libc cannot be used because it links -// to the standard library (e.g. `#![no_std]` isn't stable yet), so that's why -// this specifically requires the in-tree version. -#![feature(libc)] -extern crate libc; - -// Listed below are the five allocation functions currently required by custom -// allocators. Their signatures and symbol names are not currently typechecked -// by the compiler, but this is a future extension and are required to match -// what is found below. -// -// Note that the standard `malloc` and `realloc` functions do not provide a way -// to communicate alignment so this implementation would need to be improved -// with respect to alignment in that aspect. - -#[no_mangle] -pub extern fn __rust_allocate(size: usize, _align: usize) -> *mut u8 { - unsafe { libc::malloc(size as libc::size_t) as *mut u8 } -} - -#[no_mangle] -pub extern fn __rust_allocate_zeroed(size: usize, _align: usize) -> *mut u8 { - unsafe { libc::calloc(size as libc::size_t, 1) as *mut u8 } -} - -#[no_mangle] -pub extern fn __rust_deallocate(ptr: *mut u8, _old_size: usize, _align: usize) { - unsafe { libc::free(ptr as *mut libc::c_void) } -} - -#[no_mangle] -pub extern fn __rust_reallocate(ptr: *mut u8, _old_size: usize, size: usize, - _align: usize) -> *mut u8 { - unsafe { - libc::realloc(ptr as *mut libc::c_void, size as libc::size_t) as *mut u8 - } -} - -#[no_mangle] -pub extern fn __rust_reallocate_inplace(_ptr: *mut u8, old_size: usize, - _size: usize, _align: usize) -> usize { - old_size // This api is not supported by libc. -} - -#[no_mangle] -pub extern fn __rust_usable_size(size: usize, _align: usize) -> usize { - size -} - -# // Only needed to get rustdoc to test this: -# fn main() {} -# #[lang = "panic_fmt"] fn panic_fmt() {} -# #[lang = "eh_personality"] fn eh_personality() {} -# #[lang = "eh_unwind_resume"] extern fn eh_unwind_resume() {} -# #[no_mangle] pub extern fn rust_eh_register_frames () {} -# #[no_mangle] pub extern fn rust_eh_unregister_frames () {} -``` - -After we compile this crate, it can be used as follows: - -```rust,ignore -extern crate my_allocator; - -fn main() { - let a = Box::new(8); // Allocates memory via our custom allocator crate. - println!("{}", a); -} -``` - -## Custom allocator limitations - -There are a few restrictions when working with custom allocators which may cause -compiler errors: - -* Any one artifact may only be linked to at most one allocator. Binaries, - dylibs, and staticlibs must link to exactly one allocator, and if none have - been explicitly chosen the compiler will choose one. On the other hand rlibs - do not need to link to an allocator (but still can). - -* A consumer of an allocator is tagged with `#![needs_allocator]` (e.g. the - `liballoc` crate currently) and an `#[allocator]` crate cannot transitively - depend on a crate which needs an allocator (e.g. circular dependencies are not - allowed). This basically means that allocators must restrict themselves to - libcore currently. - - diff --git a/src/doc/unstable-book/src/language-features/global-allocator.md b/src/doc/unstable-book/src/language-features/global-allocator.md new file mode 100644 index 00000000000..2eae40aef34 --- /dev/null +++ b/src/doc/unstable-book/src/language-features/global-allocator.md @@ -0,0 +1,71 @@ +# `global_allocator` + +The tracking issue for this feature is: [#27389] + +[#27389]: https://github.com/rust-lang/rust/issues/27389 + +------------------------ + +Rust programs may need to change the allocator that they're running with from +time to time. This use case is distinct from an allocator-per-collection (e.g. a +`Vec` with a custom allocator) and instead is more related to changing the +global default allocator, e.g. what `Vec<T>` uses by default. + +Currently Rust programs don't have a specified global allocator. The compiler +may link to a version of [jemalloc] on some platforms, but this is not +guaranteed. Libraries, however, like cdylibs and staticlibs are guaranteed +to use the "system allocator" which means something like `malloc` on Unixes and +`HeapAlloc` on Windows. + +[jemalloc]: https://github.com/jemalloc/jemalloc + +The `#[global_allocator]` attribute, however, allows configuring this choice. +You can use this to implement a completely custom global allocator to route all +default allocation requests to a custom object. Defined in [RFC 1974] usage +looks like: + +[RFC 1974]: https://github.com/rust-lang/rfcs/pull/1974 + +```rust +#![feature(global_allocator, heap_api)] + +use std::heap::{Alloc, System, Layout, AllocErr}; + +struct MyAllocator; + +unsafe impl<'a> Alloc for &'a MyAllocator { + unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { + System.alloc(layout) + } + + unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) { + System.dealloc(ptr, layout) + } +} + +#[global_allocator] +static GLOBAL: MyAllocator = MyAllocator; + +fn main() { + // This `Vec` will allocate memory through `GLOBAL` above + let mut v = Vec::new(); + v.push(1); +} +``` + +And that's it! The `#[global_allocator]` attribute is applied to a `static` +which implements the `Alloc` trait in the `std::heap` module. Note, though, +that the implementation is defined for `&MyAllocator`, not just `MyAllocator`. +You may wish, however, to also provide `Alloc for MyAllocator` for other use +cases. + +A crate can only have one instance of `#[global_allocator]` and this instance +may be loaded through a dependency. For example `#[global_allocator]` above +could have been placed in one of the dependencies loaded through `extern crate`. + +Note that `Alloc` itself is an `unsafe` trait, with much documentation on the +trait itself about usage and for implementors. Extra care should be taken when +implementing a global allocator as well as the allocator may be called from many +portions of the standard library, such as the panicking routine. As a result it +is highly recommended to not panic during allocation and work in as many +situations with as few dependencies as possible as well. |
