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

Add some pthread-related syscalls #20

Merged
merged 1 commit into from
Oct 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading