Thread Local buffer inside a structure

I currently have code that uses thread_local as follows.
This code is about 2 yers old.
Here is the full code

When I rustup'ed to the latest, this is now throwing an error
With the

#![feature(thread_local)]

pub struct BufWriter<W: Write> {
    inner: Option<W>,
    // #30888: If the inner writer panics in a call to write, we don't want to
    // write the buffered data a second time in BufWriter's destructor. This
    // flag tells the Drop impl if it should skip the flush.
    panicked: bool,
    #[thread_local]
    buf: [i32; libc::PIPE_BUF],
    #[thread_local]
    ind: usize,
}

impl<W: Write> BufWriter<W> {
    pub fn new(inner: W) -> BufWriter<W> {
        BufWriter {
            inner: Some(inner),
            panicked: false,
            buf: [0; libc::PIPE_BUF],
            ind: 0,
        }
    }
}

impl<W: Write> fmt::Debug for BufWriter<W>
where
    W: fmt::Debug,
{
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt.debug_struct("BufWriter")
            .field("writer", &self.inner.as_ref().unwrap())
            .field("buffer", &format_args!("{}/{}", self.buf.len(), libc::PIPE_BUF))
            .finish()
    }
}

This is now throwing an error

error: attribute should be applied to a static
  --> src/bufwriter.rs:19:5
   |
19 |     #[thread_local]
   |     ^^^^^^^^^^^^^^^
20 |     buf: [i32; libc::PIPE_BUF],
   |     -------------------------- not a static

error: attribute should be applied to a static
  --> src/bufwriter.rs:21:5
   |
21 |     #[thread_local]
   |     ^^^^^^^^^^^^^^^
22 |     ind: usize,
   |     ---------- not a static

This has been working so far and has started failing after upgrading to the latest compiler.
This seems to have changed is not supported amyore.

How is this supposed to work now.
I need the buf array and ind variable inside pub struct BufWriter<W: Write> to be thread local so that this can work in a multi threaded environment.

I am pretty certain the #[thread_local] never had any effect. It just silently ignored it in the past.

1 Like

It isn't supposed to work. It doesn't make sense to put a #[thread_local] inside a type. A thread-local is effectively a global variable. That contradicts being the member of another type (as a struct/tuple field or enum variant), because one can arbitrarily instantiate composite types, so their members are obviously not global.

What you had so far didn't make sense and probably didn't really work as you wanted it to work.

This code is part of a LD_PRELOAD program.
That will be writing to a buffer/file/pipe data about how is opening what files.
The code that does it uses this buffWriter to write data into a shared pipe/file for the process.
If the process happens to be multiple threads, I dont want the writes from different threads to gets mixed up.

If I remove thread _local, can I still maintain that expectation?

I feel like this is the wrong question. As others said, thread_local never worked for fields, so you can remove it and nothing will change. However, you should question if your expectation was met in the first place.

2 Likes