]>
Commit | Line | Data |
---|---|---|
84060bad RM |
1 | /* pthread_getcpuclockid -- Get POSIX clockid_t for a pthread_t. Linux version |
2 | Copyright (C) 2000, 2001, 2004 Free Software Foundation, Inc. | |
a334319f UD |
3 | This file is part of the GNU C Library. |
4 | ||
5 | The GNU C Library is free software; you can redistribute it and/or | |
6 | modify it under the terms of the GNU Lesser General Public License as | |
7 | published by the Free Software Foundation; either version 2.1 of the | |
8 | License, or (at your option) any later version. | |
9 | ||
10 | The GNU C Library is distributed in the hope that it will be useful, | |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 | Lesser General Public License for more details. | |
14 | ||
15 | You should have received a copy of the GNU Lesser General Public | |
16 | License along with the GNU C Library; see the file COPYING.LIB. If not, | |
17 | write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
18 | Boston, MA 02111-1307, USA. */ | |
19 | ||
20 | #include <errno.h> | |
21 | #include <pthread.h> | |
22 | #include <sys/time.h> | |
23 | #include <time.h> | |
24 | #include <internals.h> | |
84060bad RM |
25 | #include "kernel-features.h" |
26 | #include "posix-cpu-timers.h" | |
27 | ||
28 | ||
29 | #if !(__ASSUME_POSIX_CPU_TIMERS > 0) | |
30 | int __libc_missing_posix_cpu_timers attribute_hidden; | |
31 | #endif | |
32 | #if !(__ASSUME_POSIX_TIMERS > 0) | |
33 | int __libc_missing_posix_timers attribute_hidden; | |
34 | #endif | |
a334319f UD |
35 | |
36 | int | |
37 | pthread_getcpuclockid (pthread_t thread_id, clockid_t *clock_id) | |
38 | { | |
84060bad RM |
39 | #ifdef __NR_clock_getres |
40 | pthread_handle handle = thread_handle(thread_id); | |
41 | int pid; | |
42 | ||
43 | __pthread_lock (&handle->h_lock, NULL); | |
44 | if (nonexisting_handle (handle, thread_id)) | |
45 | { | |
46 | __pthread_unlock (&handle->h_lock); | |
47 | return ESRCH; | |
48 | } | |
49 | pid = handle->h_descr->p_pid; | |
50 | __pthread_unlock (&handle->h_lock); | |
51 | ||
52 | /* The clockid_t value is a simple computation from the PID. | |
53 | But we do a clock_getres call to validate it if we aren't | |
54 | yet sure we have the kernel support. */ | |
55 | ||
56 | const clockid_t pidclock = MAKE_PROCESS_CPUCLOCK (pid, CPUCLOCK_SCHED); | |
57 | ||
58 | # if !(__ASSUME_POSIX_CPU_TIMERS > 0) | |
59 | # if !(__ASSUME_POSIX_TIMERS > 0) | |
60 | if (__libc_missing_posix_timers && !__libc_missing_posix_cpu_timers) | |
61 | __libc_missing_cpu_posix_timers = 1; | |
62 | # endif | |
63 | if (!__libc_missing_posix_cpu_timers) | |
64 | { | |
65 | INTERNAL_SYSCALL_DECL (err); | |
66 | int r = INTERNAL_SYSCALL (clock_getres, err, 2, tidclock, NULL); | |
67 | if (!INTERNAL_SYSCALL_ERROR_P (r, err)) | |
68 | # endif | |
69 | { | |
70 | *clock_id = pidclock; | |
71 | return 0; | |
72 | } | |
73 | ||
74 | # if !(__ASSUME_POSIX_CPU_TIMERS > 0) | |
75 | # if !(__ASSUME_POSIX_TIMERS > 0) | |
76 | if (INTERNAL_SYSCALL_ERRNO (r, err) == ENOSYS) | |
77 | { | |
78 | /* The kernel doesn't support these calls at all. */ | |
79 | __libc_missing_posix_timers = 1; | |
80 | __libc_missing_posix_cpu_timers = 1; | |
81 | } | |
82 | else | |
83 | # endif | |
84 | if (INTERNAL_SYSCALL_ERRNO (r, err) == EINVAL) | |
85 | { | |
86 | /* The kernel doesn't support these clocks at all. */ | |
87 | __libc_missing_posix_cpu_timers = 1; | |
88 | } | |
89 | else | |
90 | return INTERNAL_SYSCALL_ERRNO (r, err); | |
91 | } | |
92 | # endif | |
93 | #endif | |
94 | ||
a334319f UD |
95 | #ifdef CLOCK_THREAD_CPUTIME_ID |
96 | /* We need to store the thread ID in the CLOCKID variable together | |
97 | with a number identifying the clock. We reserve the low 3 bits | |
98 | for the clock ID and the rest for the thread ID. This is | |
99 | problematic if the thread ID is too large. But 29 bits should be | |
100 | fine. | |
101 | ||
102 | If some day more clock IDs are needed the ID part can be | |
103 | enlarged. The IDs are entirely internal. */ | |
104 | if (2 * PTHREAD_THREADS_MAX | |
105 | >= 1 << (8 * sizeof (*clock_id) - CLOCK_IDFIELD_SIZE)) | |
106 | return ERANGE; | |
107 | ||
108 | /* Store the number. */ | |
109 | *clock_id = CLOCK_THREAD_CPUTIME_ID | (thread_id << CLOCK_IDFIELD_SIZE); | |
110 | ||
111 | return 0; | |
112 | #else | |
113 | /* We don't have a timer for that. */ | |
114 | return ENOENT; | |
115 | #endif | |
116 | } |