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

Is there a crate here that can quickly create new threads? #98

Closed
CtrlZ233 opened this issue Feb 21, 2024 · 4 comments
Closed

Is there a crate here that can quickly create new threads? #98

CtrlZ233 opened this issue Feb 21, 2024 · 4 comments

Comments

@CtrlZ233
Copy link

When I created the thread, I found that the tls segment was difficult to process. Is there a crate here that can quickly create new threads?

@nspin
Copy link
Member

nspin commented Feb 22, 2024

This project’s current focus is more on the lower-level side of things, so we don’t yet have higher-level dynamic libraries like those in seL4_libs.

However, I’m eager to help you with this code you’re working on! If you are able to provide more detail about the context, I might be able to give you some pointers, add an example to ./crates/private/tests, or even adjust or extend this project’s APIs to make the task you’re facing easier.

@CtrlZ233
Copy link
Author

CtrlZ233 commented Feb 23, 2024

This is just a small demo on riscv plat, I'm not sure if this is the right thing to do.
I allocated a tcb object and configured the same cspace and vspace as the root task

tcb.tcb_configure(ep.cptr(), cnode, CNodeCapData::new(0, 0), vspace, ipc_buffer_addr as u64, ipc_buffer)?;

Then I applied for a UserContext and assigned values to the pc register and sp register, but I'm not sure how to assign values to the tp register and gp register, so I assign the corresponding registers of the root task to them.

let mut user_context = tcb.tcb_read_registers(false, (core::mem::size_of::<UserContext>() / sel4::WORD_SIZE) as u64)?;
*(user_context.pc_mut()) = unsafe { core::mem::transmute(func) };
*(user_context.sp_mut()) = unsafe {
    NEW_STACK.as_ptr().add(4096) as u64
};
let tp: u64;
unsafe {
    asm!("mv {}, tp", out(reg) tp);
}
let gp: u64;
unsafe {
   asm!("mv {}, gp", out(reg) gp);
}
user_context.inner_mut().tp = tp;
user_context.inner_mut().gp = gp;
user_context.inner_mut().a0 = args as u64;
tcb.tcb_write_all_registers(false, &mut user_context)?;
tcb.tcb_set_affinity(1)?;
tcb.tcb_resume()?;

When I access thread local variables (like ipc buffer) in a new thread, the address is the same as the root task. How should I set the tp register of the new thread?

@nspin
Copy link
Member

nspin commented Feb 26, 2024

I've added an example in #99 that demonstrates a root task that spawns a secondary thread.

Motivated by this issue, I've also redesigned the sel4-initialize-tls crate (also in #99). This crate now exposes an API that encapsulates arch-specific details of TLS region handling to support cases such as the new example and your scenario.

In the new example and in your scenario, the new thread requires an initialized TLS region, along with a pointer to an arch-specific offset into that region in user_context.inner_mut().tp. If you are using LLD without a custom linker script, the information needed to initialize a TLS region is embedded into the binary via PHDRS. In the new spawn-thread example, this information is gathered via the get_tls_image() function. You can, of course, include the TLS image in the binary in a custom linker script, too. The TlsReservation struct uses the sel4-initialize-tls crate to allocate a block of memory with the proper size and alignment, initialize it according to the TLS image, and then compute the proper value for the new thread's thread pointer (.tp).

The new thread's TLS region is initialized according to the program image, so the thread-local IPC buffer variable will not be set. In the new example, the first thing the new thread does is set it via the sel4 crate's API.

@CtrlZ233
Copy link
Author

CtrlZ233 commented Mar 4, 2024

I've added an example in #99 that demonstrates a root task that spawns a secondary thread.

Motivated by this issue, I've also redesigned the sel4-initialize-tls crate (also in #99). This crate now exposes an API that encapsulates arch-specific details of TLS region handling to support cases such as the new example and your scenario.

In the new example and in your scenario, the new thread requires an initialized TLS region, along with a pointer to an arch-specific offset into that region in user_context.inner_mut().tp. If you are using LLD without a custom linker script, the information needed to initialize a TLS region is embedded into the binary via PHDRS. In the new spawn-thread example, this information is gathered via the get_tls_image() function. You can, of course, include the TLS image in the binary in a custom linker script, too. The TlsReservation struct uses the sel4-initialize-tls crate to allocate a block of memory with the proper size and alignment, initialize it according to the TLS image, and then compute the proper value for the new thread's thread pointer (.tp).

The new thread's TLS region is initialized according to the program image, so the thread-local IPC buffer variable will not be set. In the new example, the first thing the new thread does is set it via the sel4 crate's API.

OK, got it, thanks.

@CtrlZ233 CtrlZ233 closed this as completed Mar 4, 2024
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

No branches or pull requests

2 participants