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));
|
void (*child)(void));
|
||||||
extern int pthread_once(pthread_once_t *once_control,
|
extern int pthread_once(pthread_once_t *once_control,
|
||||||
void (*init_routine)(void));
|
void (*init_routine)(void));
|
||||||
|
extern int pthread_getcpuclockid(pthread_t thread_id, clockid_t* clock_id);
|
||||||
|
|
||||||
/* thread attributes functions */
|
/* thread attributes functions */
|
||||||
extern int pthread_attr_destroy(pthread_attr_t *attr);
|
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_get_clock(clockid_t clockID, bigtime_t* _time);
|
||||||
status_t _user_set_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,
|
int32 _user_create_timer(clockid_t clockID, thread_id threadID,
|
||||||
uint32 flags, const struct sigevent* event,
|
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_get_clock(clockid_t clockID, bigtime_t* _time);
|
||||||
extern status_t _kern_set_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 bigtime_t _kern_system_time();
|
||||||
extern status_t _kern_snooze_etc(bigtime_t time, int timebase, int32 flags,
|
extern status_t _kern_snooze_etc(bigtime_t time, int timebase, int32 flags,
|
||||||
|
@ -14,12 +14,19 @@
|
|||||||
#include <debug.h>
|
#include <debug.h>
|
||||||
#include <kernel.h>
|
#include <kernel.h>
|
||||||
#include <real_time_clock.h>
|
#include <real_time_clock.h>
|
||||||
|
#include <syscall_clock_info.h>
|
||||||
#include <team.h>
|
#include <team.h>
|
||||||
#include <thread_types.h>
|
#include <thread_types.h>
|
||||||
#include <UserEvent.h>
|
#include <UserEvent.h>
|
||||||
#include <util/AutoLock.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
|
// 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
|
// 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
|
// 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;
|
team_id teamID;
|
||||||
if (clockID == CLOCK_PROCESS_CPUTIME_ID) {
|
if (clockID == CLOCK_PROCESS_CPUTIME_ID) {
|
||||||
teamID = B_CURRENT_TEAM;
|
teamID = B_CURRENT_TEAM;
|
||||||
} else {
|
} else if ((clockID & CPUCLOCK_THREAD) == CPUCLOCK_THREAD) {
|
||||||
if (clockID < 0)
|
thread_id threadID = clockID & CPUCLOCK_ID_MASK;
|
||||||
|
// get the thread
|
||||||
|
Thread* thread = Thread::Get(threadID);
|
||||||
|
if (thread == NULL)
|
||||||
return B_BAD_VALUE;
|
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;
|
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
|
// get the team
|
||||||
@ -1657,13 +1675,31 @@ _user_set_clock(clockid_t clockID, bigtime_t time)
|
|||||||
team_id teamID;
|
team_id teamID;
|
||||||
if (clockID == CLOCK_PROCESS_CPUTIME_ID) {
|
if (clockID == CLOCK_PROCESS_CPUTIME_ID) {
|
||||||
teamID = B_CURRENT_TEAM;
|
teamID = B_CURRENT_TEAM;
|
||||||
} else {
|
} else if ((clockID & CPUCLOCK_THREAD) != 0) {
|
||||||
if (clockID < 0)
|
thread_id threadID = clockID & CPUCLOCK_ID_MASK;
|
||||||
|
if (threadID < 0)
|
||||||
return B_BAD_VALUE;
|
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;
|
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
|
// 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
|
int32
|
||||||
_user_create_timer(clockid_t clockID, thread_id threadID, uint32 flags,
|
_user_create_timer(clockid_t clockID, thread_id threadID, uint32 flags,
|
||||||
const struct sigevent* userEvent,
|
const struct sigevent* userEvent,
|
||||||
|
@ -14,8 +14,10 @@
|
|||||||
#include <OS.h>
|
#include <OS.h>
|
||||||
|
|
||||||
#include <errno_private.h>
|
#include <errno_private.h>
|
||||||
#include <time_private.h>
|
#include <pthread_private.h>
|
||||||
|
#include <syscall_clock_info.h>
|
||||||
#include <syscall_utils.h>
|
#include <syscall_utils.h>
|
||||||
|
#include <time_private.h>
|
||||||
|
|
||||||
#include <syscalls.h>
|
#include <syscalls.h>
|
||||||
|
|
||||||
@ -145,9 +147,7 @@ clock_getcpuclockid(pid_t pid, clockid_t* _clockID)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// test-get the time to verify the team exists and we have permission
|
status_t error = _kern_get_cpuclockid(pid, TEAM_ID, _clockID);
|
||||||
bigtime_t microSeconds;
|
|
||||||
status_t error = _kern_get_clock(pid, µSeconds);
|
|
||||||
if (error != B_OK) {
|
if (error != B_OK) {
|
||||||
// Since pid is > 0, B_BAD_VALUE always means a team with that ID
|
// Since pid is > 0, B_BAD_VALUE always means a team with that ID
|
||||||
// doesn't exist. Translate the error code accordingly.
|
// doesn't exist. Translate the error code accordingly.
|
||||||
@ -156,6 +156,24 @@ clock_getcpuclockid(pid_t pid, clockid_t* _clockID)
|
|||||||
return error;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -43,6 +43,7 @@ SimpleTest <test>truncate : truncate.cpp ;
|
|||||||
SimpleTest init_rld_after_fork_test : init_rld_after_fork_test.cpp ;
|
SimpleTest init_rld_after_fork_test : init_rld_after_fork_test.cpp ;
|
||||||
SimpleTest user_thread_fork_test : user_thread_fork_test.cpp ;
|
SimpleTest user_thread_fork_test : user_thread_fork_test.cpp ;
|
||||||
SimpleTest pthread_barrier_test : pthread_barrier_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_test : posix_spawn_test.cpp ;
|
||||||
SimpleTest posix_spawn_redir_test : posix_spawn_redir_test.c ;
|
SimpleTest posix_spawn_redir_test : posix_spawn_redir_test.c ;
|
||||||
SimpleTest posix_spawn_redir_err : posix_spawn_redir_err.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