Print this page
OS-???? [lx] SIGEV_THREAD_ID emulation needed
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/lib/brand/lx/lx_brand/common/clock.c
+++ new/usr/src/lib/brand/lx/lx_brand/common/clock.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
↓ open down ↓ |
17 lines elided |
↑ open up ↑ |
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
24 24 * Use is subject to license terms.
25 25 * Copyright 2015 Joyent, Inc.
26 26 */
27 27
28 +#include <sys/syscall.h>
29 +
28 30 #include <errno.h>
31 +#include <stdlib.h>
29 32 #include <string.h>
30 33 #include <time.h>
34 +#include <unistd.h>
31 35 #include <sys/resource.h>
32 36 #include <sys/lx_misc.h>
33 37 #include <sys/lx_syscall.h>
34 38 #include <lx_signum.h>
35 39
36 40 /*
37 41 * Translating from the Linux clock types to the Illumos types is a bit of a
38 42 * mess.
39 43 *
40 44 * Linux uses different values for it clock identifiers, so we have to do basic
41 45 * translations between the two. Thankfully, both Linux and Illumos implement
42 46 * the same POSIX SUSv3 clock types, so the semantics should be identical.
43 47 *
44 48 * However, CLOCK_REALTIME and CLOCK_HIGHRES (CLOCK_MONOTONIC) are the only two
45 49 * clock backends currently implemented on Illumos. Functions in the kernel
46 50 * that use the CLOCK_BACKEND macro will return an error for any clock type
47 51 * that does not exist in the clock_backend array. These functions are
48 52 * clock_settime, clock_gettime, clock_getres and timer_create.
49 53 *
50 54 * For reference, the kernel's clock_backend array looks like this:
51 55 *
52 56 * clock_backend[CLOCK_MAX] (6 entries)
53 57 * 0 __CLOCK_REALTIME0 valid ptr. (obs. same as CLOCK_REALTIME)
54 58 * 1 CLOCK_VIRTUAL NULL
55 59 * 2 CLOCK_THREAD_CPUTIME_ID NULL
56 60 * 3 CLOCK_REALTIME valid ptr.
57 61 * 4 CLOCK_MONOTONIC (CLOCK_HIGHRES) valid ptr.
58 62 * 5 CLOCK_PROCESS_CPUTIME_ID NULL
59 63 *
60 64 * See the comment on clock_highres_timer_create for full details but a zone
61 65 * needs the proc_clock_highres privilege to use the CLOCK_HIGHRES clock so it
62 66 * will generally be unusable by lx for timer_create.
63 67 */
64 68
65 69 static int ltos_clock[] = {
66 70 CLOCK_REALTIME, /* LX_CLOCK_REALTIME */
67 71 CLOCK_HIGHRES, /* LX_CLOCK_MONOTONIC */
68 72 CLOCK_PROCESS_CPUTIME_ID, /* LX_CLOCK_PROCESS_CPUTIME_ID */
69 73 CLOCK_THREAD_CPUTIME_ID, /* LX_CLOCK_THREAD_CPUTIME_ID */
70 74 CLOCK_HIGHRES, /* LX_CLOCK_MONOTONIC_RAW */
71 75 CLOCK_REALTIME, /* LX_CLOCK_REALTIME_COARSE */
72 76 CLOCK_HIGHRES /* LX_CLOCK_MONOTONIC_COARSE */
73 77 };
74 78
75 79 /*
76 80 * Since the Illumos CLOCK_HIGHRES clock requires elevated privs, which can
77 81 * lead to a DOS, we use the only other option (CLOCK_REALTIME) when given
78 82 * LX_CLOCK_MONOTONIC.
79 83 */
80 84 static int ltos_timer[] = {
81 85 CLOCK_REALTIME,
82 86 CLOCK_REALTIME,
83 87 CLOCK_THREAD_CPUTIME_ID, /* XXX thread, not process but fails */
84 88 CLOCK_THREAD_CPUTIME_ID,
85 89 CLOCK_REALTIME,
86 90 CLOCK_REALTIME,
87 91 CLOCK_REALTIME
88 92 };
89 93
90 94 #define LX_CLOCK_MAX (sizeof (ltos_clock) / sizeof (ltos_clock[0]))
91 95 #define LX_TIMER_MAX (sizeof (ltos_timer) / sizeof (ltos_timer[0]))
92 96
93 97 #define LX_SIGEV_PAD_SIZE ((64 - \
94 98 (sizeof (int) * 2 + sizeof (union sigval))) / sizeof (int))
95 99
96 100 typedef struct {
97 101 union sigval lx_sigev_value; /* same layout for both */
98 102 int lx_sigev_signo;
99 103 int lx_sigev_notify;
100 104 union {
101 105 int lx_pad[LX_SIGEV_PAD_SIZE];
102 106 int lx_tid;
103 107 struct {
104 108 void (*lx_notify_function)(union sigval);
105 109 void *lx_notify_attribute;
↓ open down ↓ |
65 lines elided |
↑ open up ↑ |
106 110 } lx_sigev_thread;
107 111 } lx_sigev_un;
108 112 } lx_sigevent_t;
109 113
110 114 /* sigevent sigev_notify conversion table */
111 115 static int ltos_sigev[] = {
112 116 SIGEV_SIGNAL,
113 117 SIGEV_NONE,
114 118 SIGEV_THREAD,
115 119 0, /* Linux skips event 3 */
116 - SIGEV_THREAD /* the Linux SIGEV_THREAD_ID */
120 + SIGEV_THREAD /* Linux SIGEV_THREAD_ID -- see lx_sigev_thread_id() */
117 121 };
118 122
119 -#define LX_SIGEV_MAX (sizeof (ltos_sigev) / sizeof (ltos_sigev[0]))
123 +#define LX_SIGEV_MAX (sizeof (ltos_sigev) / sizeof (ltos_sigev[0]))
124 +#define LX_SIGEV_THREAD_ID 4
120 125
121 126 long
122 127 lx_clock_nanosleep(int clock, int flags, struct timespec *rqtp,
123 128 struct timespec *rmtp)
124 129 {
125 130 int ret = 0;
126 131 int err;
127 132 struct timespec rqt, rmt;
128 133
129 134 if (clock < 0 || clock >= LX_CLOCK_MAX)
130 135 return (-EINVAL);
131 136
132 137 if (uucopy(rqtp, &rqt, sizeof (struct timespec)) < 0)
133 138 return (-EFAULT);
134 139
135 140 /* the TIMER_RELTIME and TIMER_ABSTIME flags are the same on Linux */
136 141 if ((err = clock_nanosleep(ltos_clock[clock], flags, &rqt, &rmt))
137 142 != 0) {
138 143 if (err != EINTR)
139 144 return (-err);
140 145 ret = -EINTR;
141 146 /*
142 147 * We fall through in case we have to pass back the remaining
143 148 * time.
144 149 */
145 150 }
146 151
147 152 /*
148 153 * Only copy values to rmtp if the timer is TIMER_RELTIME and rmtp is
149 154 * non-NULL.
150 155 */
151 156 if (((flags & TIMER_RELTIME) == TIMER_RELTIME) && (rmtp != NULL) &&
152 157 (uucopy(&rmt, rmtp, sizeof (struct timespec)) < 0))
153 158 return (-EFAULT);
154 159
155 160 return (ret);
↓ open down ↓ |
26 lines elided |
↑ open up ↑ |
156 161 }
157 162
158 163 /*ARGSUSED*/
159 164 long
160 165 lx_adjtimex(void *tp)
161 166 {
162 167 return (-EPERM);
163 168 }
164 169
165 170 /*
171 + * Notification function for use with native SIGEV_THREAD in order to
172 + * emulate Linux SIGEV_THREAD_ID. Native SIGEV_THREAD is used as the
173 + * timer mechanism and B_SIGEV_THREAD_ID performs the actual event
174 + * delivery to the appropriate lx tid.
175 + */
176 +static void
177 +lx_sigev_thread_id(union sigval sival)
178 +{
179 + lx_sigevent_t *lev = (lx_sigevent_t *)sival.sival_ptr;
180 + syscall(SYS_brand, B_SIGEV_THREAD_ID, lev->lx_sigev_un.lx_tid,
181 + lev->lx_sigev_signo, lev->lx_sigev_value);
182 + free(lev);
183 +}
184 +
185 +
186 +/*
166 187 * The Illumos timer_create man page says it accepts the following clocks:
167 188 * CLOCK_REALTIME (3) wall clock
168 189 * CLOCK_VIRTUAL (1) user CPU usage clock - No Backend
169 190 * CLOCK_PROF (2) user and system CPU usage clock - No Backend
170 191 * CLOCK_HIGHRES (4) non-adjustable, high-resolution clock
171 192 * However, in reality the Illumos timer_create only accepts CLOCK_REALTIME
172 193 * and CLOCK_HIGHRES, and since we can't use CLOCK_HIGHRES in a zone, we're
173 194 * down to one clock.
174 195 */
175 196 long
176 197 lx_timer_create(int clock, struct sigevent *lx_sevp, timer_t *tid)
177 198 {
178 199 lx_sigevent_t lev;
179 200 struct sigevent sev;
180 201
181 202 if (clock < 0 || clock >= LX_TIMER_MAX)
182 203 return (-EINVAL);
183 204
184 205 /* We have to convert the Linux sigevent layout to the Illumos layout */
185 206 if (uucopy(lx_sevp, &lev, sizeof (lev)) < 0)
↓ open down ↓ |
10 lines elided |
↑ open up ↑ |
186 207 return (-EFAULT);
187 208
188 209 if (lev.lx_sigev_notify < 0 || lev.lx_sigev_notify > LX_SIGEV_MAX)
189 210 return (-EINVAL);
190 211
191 212 sev.sigev_notify = ltos_sigev[lev.lx_sigev_notify];
192 213 sev.sigev_signo = ltos_signo[lev.lx_sigev_signo];
193 214 sev.sigev_value = lev.lx_sigev_value;
194 215
195 216 /*
196 - * The sigevent sigev_notify_function and sigev_notify_attributes
197 - * members are not used by timer_create, so no conversion is needed.
217 + * Assume all Linux libc implementations map SIGEV_THREAD to
218 + * SIGEV_THREAD_ID and ignore passed-in attributes.
198 219 */
220 + sev.sigev_notify_attributes = NULL;
199 221
222 + if (lev.lx_sigev_notify == LX_SIGEV_THREAD_ID) {
223 + pid_t caller_pid = getpid();
224 + pid_t target_pid;
225 + int rval;
226 +
227 + if ((rval = lx_lpid_to_spair(lev.lx_sigev_un.lx_tid,
228 + &target_pid, NULL)) != 0) {
229 +
230 + /*
231 + * Attempt to stick to the defined ERRORS in
232 + * timer_create(2).
233 + */
234 + if (rval == -ESRCH)
235 + return (-EINVAL);
236 +
237 + return (rval);
238 + }
239 +
240 + /*
241 + * The caller of SIGEV_THREAD_ID must be in the same
242 + * process as the target thread.
243 + */
244 + if (caller_pid != target_pid)
245 + return (-EINVAL);
246 +
247 + /*
248 + * Pass the original lx sigevent_t to the native
249 + * notify function so that it may pass it to the lx
250 + * helper thread. It is the responsibility of
251 + * lx_sigev_thread_id() to free lev_copy after the
252 + * information is relayed to lx.
253 + */
254 + lx_sigevent_t *lev_copy = malloc(sizeof (lx_sigevent_t));
255 + if (lev_copy == NULL)
256 + return (-ENOMEM);
257 +
258 + if (uucopy(&lev, lev_copy, sizeof (lx_sigevent_t)) < 0) {
259 + free(lev_copy);
260 + return (-EFAULT);
261 + }
262 +
263 + sev.sigev_notify_function = lx_sigev_thread_id;
264 + sev.sigev_value.sival_ptr = lev_copy;
265 + }
266 +
200 267 return ((timer_create(ltos_timer[clock], &sev, tid) < 0) ? -errno : 0);
201 268 }
202 269
203 270 long
204 271 lx_timer_settime(timer_t tid, int flags, struct itimerspec *new_val,
205 272 struct itimerspec *old_val)
206 273 {
207 274 return ((timer_settime(tid, flags, new_val, old_val) < 0) ? -errno : 0);
208 275 }
209 276
210 277 long
211 278 lx_timer_gettime(timer_t tid, struct itimerspec *val)
212 279 {
213 280 return ((timer_gettime(tid, val) < 0) ? -errno : 0);
214 281 }
215 282
216 283 long
217 284 lx_timer_getoverrun(timer_t tid)
218 285 {
219 286 int val;
220 287
221 288 val = timer_getoverrun(tid);
222 289 return ((val < 0) ? -errno : val);
223 290 }
224 291
225 292 long
226 293 lx_timer_delete(timer_t tid)
227 294 {
228 295 return ((timer_delete(tid) < 0) ? -errno : 0);
229 296 }
↓ open down ↓ |
20 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX