Is per-CPU var same as thread local storage? Can I use TLS with %gs?

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
songziming
Member
Member
Posts: 70
Joined: Fri Jun 28, 2013 1:48 am
Contact:

Is per-CPU var same as thread local storage? Can I use TLS with %gs?

Post by songziming »

I use %gs as prefix for per-cpu vars. Offset to per-cpu area is kernel only, so I need to swapgs when switching between kernel mode and user mode.

In the code, I use macro and inline assembly to access per-cpu vars of current CPU, just use movsq with %gs prefix.

Recently I heard thread local storage (TLS), and it uses %fs as prefix. What's good about TLS is compilers have good support for it. Just mark the variable with __thread and access it, compiler will generate code with %fs prefix automatically.

It seems per-cpu variables are just kernel version of TLS. Sometimes I need to access per-cpu var of another CPU, but most time I just access per-cpu var of current CPU. So is there a way to configure GCC to use %gs as TLS self pointer? Since x86 only has swapgs, no swapfs.

If I can make kernel TLS use %gs, then the thiscpu() macro can be completely removed, code will be alot simpler.

Thanks.
Reinventing the Wheel, code: https://github.com/songziming/wheel
nullplan
Member
Member
Posts: 1789
Joined: Wed Aug 30, 2017 8:24 am

Re: Is per-CPU var same as thread local storage? Can I use TLS with %gs?

Post by nullplan »

__thread makes many assumptions about how your %fs is set up, and setting it up correctly is not simple. For example, you would need to allocate your TLS and CPU descriptor consecutively, and put your %fs between them. There is also no convenient swapfs instruction, like there is for %gs.

If you want to use fewer macros, I would suggest collecting all per-cpu variables into a structure. Call it "struct cpu". Then start that structure with a pointer to self:

Code: Select all

struct cpu {
  struct cpu *self;
  int nr;
  ...
The set %gs to point at the correct struct cpu, and then you can use a trick like this:

Code: Select all

static inline struct cpu *cpu_self(void) {
  struct cpu *r;
  __asm__("mov %%gs:0, %0" : "=r"(r));
  return r;
}
And now you can use the CPU pointer like all other pointers.
Carpe diem!
Octocontrabass
Member
Member
Posts: 5560
Joined: Mon Mar 25, 2013 7:01 pm

Re: Is per-CPU var same as thread local storage? Can I use TLS with %gs?

Post by Octocontrabass »

I don't know of any easy way to change which register GCC uses for thread-local storage, but maybe named address spaces are closer to what you want.

This can be combined with nullplan's suggestion of using a struct that points to itself, like so:

Code: Select all

static inline struct cpu *cpu_self(void) {
    return ((__seg_gs struct cpu *)0)->self;
}
Post Reply