Skip to content

Commit

Permalink
add pthread_key_* and pthread_*specific series syscalls to suppor…
Browse files Browse the repository at this point in the history
…t TSD
  • Loading branch information
AuYang261 committed Oct 30, 2023
1 parent 3c71c06 commit 1b9bf71
Show file tree
Hide file tree
Showing 24 changed files with 546 additions and 18 deletions.
1 change: 1 addition & 0 deletions api/arceos_posix_api/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ typedef struct {{
"pthread_attr_t",
"pthread_mutex_t",
"pthread_mutexattr_t",
"pthread_key_t",
"pollfd",
"nfds_t",
"epoll_event",
Expand Down
44 changes: 44 additions & 0 deletions api/arceos_posix_api/src/imp/pthread/condvar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,25 @@ impl Condvar {
Ok(())
}

fn timedwait(
&self,
mutex: *mut ctypes::pthread_mutex_t,
abstime: *const ctypes::timespec,
) -> LinuxResult {
let ret = sys_pthread_mutex_unlock(mutex);
if ret < 0 {
return Err(axerrno::LinuxError::try_from(ret).unwrap());
}
self.wq
.wait_timeout(core::time::Duration::from(unsafe { *abstime }));

let ret = sys_pthread_mutex_lock(mutex);
if ret < 0 {
return Err(axerrno::LinuxError::try_from(ret).unwrap());
}
Ok(())
}

fn notify_one(&self) -> LinuxResult {
self.wq.notify_one(true);
Ok(())
Expand All @@ -63,6 +82,31 @@ pub unsafe fn sys_pthread_cond_init(
})
}

/// Destroy a condition variable
pub unsafe fn sys_pthread_cond_destroy(condvar: *mut ctypes::pthread_cond_t) -> c_int {
debug!("sys_pthread_cond_destroy <= {:#x}", condvar as usize);
syscall_body!(sys_pthread_cond_destroy, {
condvar.cast::<Condvar>().drop_in_place();
Ok(0)
})
}

/// Wait for the condition variable to be signaled or timeout
pub unsafe fn sys_pthread_cond_timedwait(
condvar: *mut ctypes::pthread_cond_t,
mutex: *mut ctypes::pthread_mutex_t,
abstime: *const ctypes::timespec,
) -> c_int {
debug!(
"sys_pthread_cond_timedwait <= {:#x}, {:#x}, {:#x}",
condvar as usize, mutex as usize, abstime as usize
);
syscall_body!(sys_pthread_cond_timedwait, {
(*condvar.cast::<Condvar>()).timedwait(mutex, abstime)?;
Ok(0)
})
}

/// Wait for the condition variable to be signaled
pub unsafe fn sys_pthread_cond_wait(
condvar: *mut ctypes::pthread_cond_t,
Expand Down
1 change: 1 addition & 0 deletions api/arceos_posix_api/src/imp/pthread/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ use crate::ctypes;

pub mod condvar;
pub mod mutex;
pub mod tsd;

lazy_static::lazy_static! {
static ref TID_TO_PTHREAD: RwLock<BTreeMap<u64, ForceSendSync<ctypes::pthread_t>>> = {
Expand Down
12 changes: 12 additions & 0 deletions api/arceos_posix_api/src/imp/pthread/mutex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,18 @@ pub fn sys_pthread_mutex_init(
})
}

/// Destroy the given mutex.
pub fn sys_pthread_mutex_destroy(mutex: *mut ctypes::pthread_mutex_t) -> c_int {
debug!("sys_pthread_mutex_destroy <= {:#x}", mutex as usize);
syscall_body!(sys_pthread_mutex_destroy, {
check_null_mut_ptr(mutex)?;
unsafe {
mutex.cast::<PthreadMutex>().drop_in_place();
}
Ok(0)
})
}

/// Lock the given mutex.
pub fn sys_pthread_mutex_lock(mutex: *mut ctypes::pthread_mutex_t) -> c_int {
debug!("sys_pthread_mutex_lock <= {:#x}", mutex as usize);
Expand Down
68 changes: 68 additions & 0 deletions api/arceos_posix_api/src/imp/pthread/tsd.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/* Copyright (c) [2023] [Syswonder Community]
* [Rukos] is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/

use crate::ctypes;
use axerrno::LinuxError;
use axtask::tsd::DestrFunction;
use core::ffi::{c_int, c_void};

/// Allocate a specific key for a process shared by all threads.
pub unsafe fn sys_pthread_key_create(
key: *mut ctypes::pthread_key_t,
destr_function: Option<DestrFunction>,
) -> c_int {
debug!("sys_pthread_key_create <= {:#x}", key as usize);
syscall_body!(sys_pthread_key_create, {
if let Some(k) = axtask::current().alloc_key(destr_function) {
unsafe {
*key = k as ctypes::pthread_key_t;
}
Ok(0)
} else {
Err(LinuxError::EAGAIN)
}
})
}

/// Destroy a specific key for a process.
pub fn sys_pthread_key_delete(key: ctypes::pthread_key_t) -> c_int {
debug!("sys_pthread_key_delete <= {}", key);
syscall_body!(sys_pthread_key_delete, {
if let Some(_) = axtask::current().free_key(key as usize) {
Ok(0)
} else {
Err(LinuxError::EINVAL)
}
})
}

/// Set the value of a specific key for a thread.
pub fn sys_pthread_setspecific(key: ctypes::pthread_key_t, value: *const c_void) -> c_int {
debug!("sys_pthread_setspecific <= {}, {:#x}", key, value as usize);
syscall_body!(sys_pthread_setspecific, {
if let Some(_) = axtask::current().set_tsd(key as usize, value as *mut c_void) {
Ok(0)
} else {
Err(LinuxError::EINVAL)
}
})
}

/// Get the value of a specific key for a thread.
pub fn sys_pthread_getspecific(key: ctypes::pthread_key_t) -> *mut c_void {
debug!("sys_pthread_getspecific <= {}", key);
syscall_body!(sys_pthread_getspecific, {
if let Some(tsd) = axtask::current().get_tsd(key as usize) {
Ok(tsd)
} else {
// return null
Ok(core::ptr::null_mut())
}
})
}
13 changes: 9 additions & 4 deletions api/arceos_posix_api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,13 +74,18 @@ pub use imp::net::{
pub use imp::pipe::sys_pipe;
#[cfg(feature = "multitask")]
pub use imp::pthread::condvar::{
sys_pthread_cond_broadcast, sys_pthread_cond_init, sys_pthread_cond_signal,
sys_pthread_cond_wait,
sys_pthread_cond_broadcast, sys_pthread_cond_destroy, sys_pthread_cond_init,
sys_pthread_cond_signal, sys_pthread_cond_timedwait, sys_pthread_cond_wait,
};
#[cfg(feature = "multitask")]
pub use imp::pthread::mutex::{
sys_pthread_mutex_init, sys_pthread_mutex_lock, sys_pthread_mutex_trylock,
sys_pthread_mutex_unlock,
sys_pthread_mutex_destroy, sys_pthread_mutex_init, sys_pthread_mutex_lock,
sys_pthread_mutex_trylock, sys_pthread_mutex_unlock,
};
#[cfg(feature = "multitask")]
pub use imp::pthread::tsd::{
sys_pthread_getspecific, sys_pthread_key_create, sys_pthread_key_delete,
sys_pthread_setspecific,
};
#[cfg(feature = "multitask")]
pub use imp::pthread::{sys_pthread_create, sys_pthread_exit, sys_pthread_join, sys_pthread_self};
9 changes: 8 additions & 1 deletion apps/c/pthread/basic/expect_info_smp4_fifo.out
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,14 @@ test_create_exit: Exit message
test_mutex: data = 100
Second want to continue,but need to wait A=1
Second: A is 0
First work, Change A --> 1 and wakeup Second
First work, Change A --> 1 and wakeup Second or Third
A is 1, Second can work now
Third want to continue,but need to wait A=1
Third: A is 0, awake count: 1
Third: A is 0, awake count: 2
Third: A is 0, awake count: 3
First work, Change A --> 1 and wakeup Second or Third
Third: pthread_cond_timedwait success
A is 1, Third can work now
(C)Pthread basic tests run OK!
Shutting down...
1 change: 1 addition & 0 deletions apps/c/pthread/basic/features.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
alloc
paging
multitask
irq
48 changes: 43 additions & 5 deletions apps/c/pthread/basic/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A
* PARTICULAR PURPOSE. See the Mulan PSL v2 for more details.
*/

#include <assert.h>
Expand Down Expand Up @@ -133,13 +134,12 @@ int A = 0;
void *first(void *arg)
{
sleep(5);
puts("First work, Change A --> 1 and wakeup Second");
puts("First work, Change A --> 1 and wakeup Second or Third");
pthread_mutex_lock(&lock);
A = 1;
pthread_cond_signal(&condvar);
pthread_mutex_unlock(&lock);
return NULL;

}

void *second(void *arg)
Expand All @@ -155,6 +155,30 @@ void *second(void *arg)
return NULL;
}

void *third(void *arg)
{
struct timespec ts;
ts.tv_nsec = 0;
puts("Third want to continue,but need to wait A=1");
pthread_mutex_lock(&lock);
int cnt = 0;
while (A == 0) {
cnt++;
printf("Third: A is %d, awake count: %d\n", A, cnt);
ts.tv_sec = time(NULL) + 2;
pthread_cond_timedwait(&condvar, &lock, &ts);
}
// condvar should be signaled three times for three 2s intervals in 5s total
if (cnt != 3) {
puts("Third: pthread_cond_timedwait fail");
} else {
puts("Third: pthread_cond_timedwait success");
}
printf("A is %d, Third can work now\n", A);
pthread_mutex_unlock(&lock);
return NULL;
}

void test_condvar()
{
pthread_t t1, t2;
Expand All @@ -165,6 +189,18 @@ void test_condvar()

pthread_join(t1, NULL);
pthread_join(t2, NULL);
pthread_cond_destroy(&condvar);

A = 0;

pthread_cond_init(&condvar, NULL);

pthread_create(&t1, NULL, first, NULL);
pthread_create(&t2, NULL, third, NULL);

pthread_join(t1, NULL);
pthread_join(t2, NULL);
pthread_cond_destroy(&condvar);
}

int main()
Expand All @@ -175,7 +211,9 @@ int main()
test_create_join();
test_create_exit();
test_mutex();
test_condvar();
test_condvar();
pthread_mutex_destroy(&lock);

puts("(C)Pthread basic tests run OK!");

return 0;
Expand Down
22 changes: 22 additions & 0 deletions apps/c/pthread/tsd/expect_info_smp4_fifo.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
smp = 4
build_mode = release
log_level = info

CPU 0 started
Found physcial memory regions:
.text (READ | EXECUTE | RESERVED)
.rodata (READ | RESERVED)
.data .tdata .tbss .percpu (READ | WRITE | RESERVED)
.percpu (READ | WRITE | RESERVED)
boot stack (READ | WRITE | RESERVED)
.bss (READ | WRITE | RESERVED)
free memory (READ | WRITE | FREE)
Initialize global memory allocator...
Initialize kernel page table...
Initialize platform devices...
Initialize scheduling...
use FIFO scheduler.
max_keys = 1024, got No.0
TSD test success
(C)Pthread TSD tests run OK!
Shutting down...
4 changes: 4 additions & 0 deletions apps/c/pthread/tsd/features.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
alloc
paging
multitask
irq
74 changes: 74 additions & 0 deletions apps/c/pthread/tsd/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/* Copyright (c) [2023] [Syswonder Community]
* [Rukos] is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A
* PARTICULAR PURPOSE. See the Mulan PSL v2 for more details.
*/

#include <assert.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

static pthread_key_t p_key;

void *specific_func(void *arg)
{
int *p = (int *)malloc(sizeof(int));
*p = *(int *)arg;
pthread_setspecific(p_key, p);
sleep(1);
int *tmp = (int *)pthread_getspecific(p_key);
assert(*tmp == *(int *)arg);
assert(pthread_getspecific(999999) == NULL);
return NULL;
}

int res = 0;

void destr_func(void *arg)
{
res += *(int *)arg;
free(arg);
// It seems that printing in destr_func will cause deadlock
// char *buf[100];
// sprintf(buf, "destr_func: %d", *(int *)arg);
// puts(buf);
}

void test_specific()
{
int max_keys = sysconf(_SC_THREAD_KEYS_MAX);
pthread_key_create(&p_key, destr_func);
printf("max_keys = %d, got No.%d\n", max_keys, p_key);

pthread_t t1, t2;
int arg1 = 0x1234, arg2 = 0x5678;
pthread_create(&t1, NULL, specific_func, &arg1);
pthread_create(&t2, NULL, specific_func, &arg2);
pthread_join(t1, NULL);
pthread_join(t2, NULL);
if (res != 0x1234 + 0x5678) {
puts("TSD test fail");
} else {
puts("TSD test success");
}

pthread_key_delete(p_key);
}

int main()
{
pthread_t main_thread = pthread_self();
assert(main_thread != 0);

test_specific();

puts("(C)Pthread TSD tests run OK!");

return 0;
}
2 changes: 2 additions & 0 deletions apps/c/pthread/tsd/test_cmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
test_one "SMP=4 LOG=info" "expect_info_smp4_fifo.out"
rm -f $APP/*.o
Loading

0 comments on commit 1b9bf71

Please sign in to comment.