mirror of
https://review.haiku-os.org/haiku
synced 2025-01-18 12:38:51 +01:00
POSIX: add pthread_getcpuclockid()
fix #15615 Change-Id: I6b34f97464fac97d0b339fa338cfc5df34536080 Reviewed-on: https://review.haiku-os.org/c/haiku/+/8681 Reviewed-by: Jérôme Duval <jerome.duval@gmail.com> Reviewed-by: waddlesplash <waddlesplash@gmail.com> Tested-by: Commit checker robot <no-reply+buildbot@haiku-os.org>
This commit is contained in:
parent
1ad6193d82
commit
04c90835ac
@ -196,6 +196,7 @@ extern int pthread_atfork(void (*prepare)(void), void (*parent)(void),
|
||||
void (*child)(void));
|
||||
extern int pthread_once(pthread_once_t *once_control,
|
||||
void (*init_routine)(void));
|
||||
extern int pthread_getcpuclockid(pthread_t thread_id, clockid_t* clock_id);
|
||||
|
||||
/* thread attributes functions */
|
||||
extern int pthread_attr_destroy(pthread_attr_t *attr);
|
||||
|
@ -261,6 +261,7 @@ void user_timer_check_team_user_timers(Team* team);
|
||||
|
||||
status_t _user_get_clock(clockid_t clockID, bigtime_t* _time);
|
||||
status_t _user_set_clock(clockid_t clockID, bigtime_t time);
|
||||
status_t _user_get_cpuclockid(thread_id id, int32 which, clockid_t* _clockID);
|
||||
|
||||
int32 _user_create_timer(clockid_t clockID, thread_id threadID,
|
||||
uint32 flags, const struct sigevent* event,
|
||||
|
15
headers/private/system/syscall_clock_info.h
Normal file
15
headers/private/system/syscall_clock_info.h
Normal file
@ -0,0 +1,15 @@
|
||||
/*
|
||||
* Copyright 2024, Jérôme Duval, jerome.duval@gmail.com. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef _SYSTEM_SYSCALL_CLOCK_INFO_H
|
||||
#define _SYSTEM_SYSCALL_CLOCK_INFO_H
|
||||
|
||||
|
||||
enum which_process_info {
|
||||
TEAM_ID = 1,
|
||||
THREAD_ID,
|
||||
};
|
||||
|
||||
|
||||
#endif /* _SYSTEM_SYSCALL_CLOCK_INFO_H */
|
@ -412,6 +412,7 @@ extern status_t _kern_get_real_time_clock_is_gmt(bool *_isGMT);
|
||||
|
||||
extern status_t _kern_get_clock(clockid_t clockID, bigtime_t* _time);
|
||||
extern status_t _kern_set_clock(clockid_t clockID, bigtime_t time);
|
||||
extern status_t _kern_get_cpuclockid(thread_id id, int32 which, clockid_t* _clockID);
|
||||
|
||||
extern bigtime_t _kern_system_time();
|
||||
extern status_t _kern_snooze_etc(bigtime_t time, int timebase, int32 flags,
|
||||
|
@ -14,12 +14,19 @@
|
||||
#include <debug.h>
|
||||
#include <kernel.h>
|
||||
#include <real_time_clock.h>
|
||||
#include <syscall_clock_info.h>
|
||||
#include <team.h>
|
||||
#include <thread_types.h>
|
||||
#include <UserEvent.h>
|
||||
#include <util/AutoLock.h>
|
||||
|
||||
|
||||
#define CPUCLOCK_TEAM 0x00000000
|
||||
#define CPUCLOCK_THREAD 0x80000000
|
||||
#define CPUCLOCK_SPECIAL 0xc0000000
|
||||
#define CPUCLOCK_ID_MASK (~(CPUCLOCK_SPECIAL))
|
||||
|
||||
|
||||
// Minimum interval length in microseconds for a periodic timer. This is not a
|
||||
// restriction on the user timer interval length itself, but the minimum time
|
||||
// span by which we advance the start time for kernel timers. A shorted user
|
||||
@ -1505,13 +1512,24 @@ user_timer_get_clock(clockid_t clockID, bigtime_t& _time)
|
||||
team_id teamID;
|
||||
if (clockID == CLOCK_PROCESS_CPUTIME_ID) {
|
||||
teamID = B_CURRENT_TEAM;
|
||||
} else {
|
||||
if (clockID < 0)
|
||||
} else if ((clockID & CPUCLOCK_THREAD) == CPUCLOCK_THREAD) {
|
||||
thread_id threadID = clockID & CPUCLOCK_ID_MASK;
|
||||
// get the thread
|
||||
Thread* thread = Thread::Get(threadID);
|
||||
if (thread == NULL)
|
||||
return B_BAD_VALUE;
|
||||
if (clockID == team_get_kernel_team_id())
|
||||
BReference<Thread> threadReference(thread, true);
|
||||
if (thread->team == team_get_kernel_team())
|
||||
return B_NOT_ALLOWED;
|
||||
// get the time
|
||||
InterruptsSpinLocker timeLocker(thread->time_lock);
|
||||
_time = thread->CPUTime(false);
|
||||
|
||||
teamID = clockID;
|
||||
return B_OK;
|
||||
} else if ((clockID & CPUCLOCK_TEAM) == CPUCLOCK_TEAM) {
|
||||
teamID = clockID & CPUCLOCK_ID_MASK;
|
||||
if (teamID == team_get_kernel_team_id())
|
||||
return B_NOT_ALLOWED;
|
||||
}
|
||||
|
||||
// get the team
|
||||
@ -1657,13 +1675,31 @@ _user_set_clock(clockid_t clockID, bigtime_t time)
|
||||
team_id teamID;
|
||||
if (clockID == CLOCK_PROCESS_CPUTIME_ID) {
|
||||
teamID = B_CURRENT_TEAM;
|
||||
} else {
|
||||
if (clockID < 0)
|
||||
} else if ((clockID & CPUCLOCK_THREAD) != 0) {
|
||||
thread_id threadID = clockID & CPUCLOCK_ID_MASK;
|
||||
if (threadID < 0)
|
||||
return B_BAD_VALUE;
|
||||
if (clockID == team_get_kernel_team_id())
|
||||
// get the thread
|
||||
Thread* thread = Thread::Get(threadID);
|
||||
if (thread == NULL)
|
||||
return B_BAD_VALUE;
|
||||
BReference<Thread> threadReference(thread, true);
|
||||
if (thread->team == team_get_kernel_team())
|
||||
return B_NOT_ALLOWED;
|
||||
|
||||
teamID = clockID;
|
||||
// set the time offset
|
||||
InterruptsSpinLocker timeLocker(thread->time_lock);
|
||||
bigtime_t diff = time - thread->CPUTime(false);
|
||||
thread->cpu_clock_offset += diff;
|
||||
|
||||
thread_clock_changed(thread, diff);
|
||||
return B_OK;
|
||||
} else {
|
||||
teamID = clockID & CPUCLOCK_ID_MASK;
|
||||
if (teamID < 0)
|
||||
return B_BAD_VALUE;
|
||||
if (teamID == team_get_kernel_team_id())
|
||||
return B_NOT_ALLOWED;
|
||||
}
|
||||
|
||||
// get the team
|
||||
@ -1686,6 +1722,34 @@ _user_set_clock(clockid_t clockID, bigtime_t time)
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
_user_get_cpuclockid(thread_id id, int32 which, clockid_t* userclockID)
|
||||
{
|
||||
clockid_t clockID;
|
||||
if (which != TEAM_ID && which != THREAD_ID)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
if (which == TEAM_ID) {
|
||||
Team* team = Team::Get(id);
|
||||
if (team == NULL)
|
||||
return B_BAD_VALUE;
|
||||
clockID = id | CPUCLOCK_TEAM;
|
||||
} else if (which == THREAD_ID) {
|
||||
Thread* thread = Thread::Get(id);
|
||||
if (thread == NULL)
|
||||
return B_BAD_VALUE;
|
||||
clockID = id | CPUCLOCK_THREAD;
|
||||
}
|
||||
|
||||
if (userclockID != NULL
|
||||
&& (!IS_USER_ADDRESS(userclockID)
|
||||
|| user_memcpy(userclockID, &clockID, sizeof(clockID)) != B_OK)) {
|
||||
return B_BAD_ADDRESS;
|
||||
}
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
int32
|
||||
_user_create_timer(clockid_t clockID, thread_id threadID, uint32 flags,
|
||||
const struct sigevent* userEvent,
|
||||
|
@ -14,8 +14,10 @@
|
||||
#include <OS.h>
|
||||
|
||||
#include <errno_private.h>
|
||||
#include <time_private.h>
|
||||
#include <pthread_private.h>
|
||||
#include <syscall_clock_info.h>
|
||||
#include <syscall_utils.h>
|
||||
#include <time_private.h>
|
||||
|
||||
#include <syscalls.h>
|
||||
|
||||
@ -145,9 +147,7 @@ clock_getcpuclockid(pid_t pid, clockid_t* _clockID)
|
||||
return 0;
|
||||
}
|
||||
|
||||
// test-get the time to verify the team exists and we have permission
|
||||
bigtime_t microSeconds;
|
||||
status_t error = _kern_get_clock(pid, µSeconds);
|
||||
status_t error = _kern_get_cpuclockid(pid, TEAM_ID, _clockID);
|
||||
if (error != B_OK) {
|
||||
// Since pid is > 0, B_BAD_VALUE always means a team with that ID
|
||||
// doesn't exist. Translate the error code accordingly.
|
||||
@ -156,6 +156,24 @@ clock_getcpuclockid(pid_t pid, clockid_t* _clockID)
|
||||
return error;
|
||||
}
|
||||
|
||||
*_clockID = pid;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
pthread_getcpuclockid(pthread_t thread, clockid_t* _clockID)
|
||||
{
|
||||
if (thread->id < 0)
|
||||
return ESRCH;
|
||||
|
||||
status_t error = _kern_get_cpuclockid(thread->id, THREAD_ID, _clockID);
|
||||
if (error != B_OK) {
|
||||
// Since thread->id is > 0, B_BAD_VALUE always means a thread with that ID
|
||||
// doesn't exist. Translate the error code accordingly.
|
||||
if (error == B_BAD_VALUE)
|
||||
return ESRCH;
|
||||
return error;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -43,6 +43,7 @@ SimpleTest <test>truncate : truncate.cpp ;
|
||||
SimpleTest init_rld_after_fork_test : init_rld_after_fork_test.cpp ;
|
||||
SimpleTest user_thread_fork_test : user_thread_fork_test.cpp ;
|
||||
SimpleTest pthread_barrier_test : pthread_barrier_test.cpp ;
|
||||
SimpleTest pthread_clock_test : pthread_clock_test.cpp ;
|
||||
SimpleTest posix_spawn_test : posix_spawn_test.cpp ;
|
||||
SimpleTest posix_spawn_redir_test : posix_spawn_redir_test.c ;
|
||||
SimpleTest posix_spawn_redir_err : posix_spawn_redir_err.c ;
|
||||
|
39
src/tests/system/libroot/posix/pthread_clock_test.cpp
Normal file
39
src/tests/system/libroot/posix/pthread_clock_test.cpp
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2024, Haiku, Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
|
||||
#include <pthread.h>
|
||||
#include <OS.h>
|
||||
|
||||
void*
|
||||
threadFn(void* ptr)
|
||||
{
|
||||
snooze(1000000);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
pthread_t t;
|
||||
pthread_create(&t, NULL, threadFn, NULL);
|
||||
|
||||
clockid_t c;
|
||||
if (pthread_getcpuclockid(t, &c) != 0)
|
||||
return 1;
|
||||
timespec ts;
|
||||
if (clock_gettime(c, &ts) != 0)
|
||||
return 1;
|
||||
|
||||
if (clock_getcpuclockid(getpid(), &c) != 0)
|
||||
return 1;
|
||||
if (clock_gettime(c, &ts) != 0)
|
||||
return 1;
|
||||
|
||||
if (pthread_join(t, NULL) != 0)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user