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>
31 34 #include <sys/resource.h>
32 35 #include <sys/lx_misc.h>
33 36 #include <sys/lx_syscall.h>
34 37 #include <lx_signum.h>
35 38
36 39 /*
37 40 * Translating from the Linux clock types to the Illumos types is a bit of a
38 41 * mess.
39 42 *
40 43 * Linux uses different values for it clock identifiers, so we have to do basic
41 44 * translations between the two. Thankfully, both Linux and Illumos implement
42 45 * the same POSIX SUSv3 clock types, so the semantics should be identical.
43 46 *
44 47 * However, CLOCK_REALTIME and CLOCK_HIGHRES (CLOCK_MONOTONIC) are the only two
45 48 * clock backends currently implemented on Illumos. Functions in the kernel
46 49 * that use the CLOCK_BACKEND macro will return an error for any clock type
47 50 * that does not exist in the clock_backend array. These functions are
48 51 * clock_settime, clock_gettime, clock_getres and timer_create.
49 52 *
50 53 * For reference, the kernel's clock_backend array looks like this:
51 54 *
52 55 * clock_backend[CLOCK_MAX] (6 entries)
53 56 * 0 __CLOCK_REALTIME0 valid ptr. (obs. same as CLOCK_REALTIME)
54 57 * 1 CLOCK_VIRTUAL NULL
55 58 * 2 CLOCK_THREAD_CPUTIME_ID NULL
56 59 * 3 CLOCK_REALTIME valid ptr.
57 60 * 4 CLOCK_MONOTONIC (CLOCK_HIGHRES) valid ptr.
58 61 * 5 CLOCK_PROCESS_CPUTIME_ID NULL
59 62 *
60 63 * See the comment on clock_highres_timer_create for full details but a zone
61 64 * needs the proc_clock_highres privilege to use the CLOCK_HIGHRES clock so it
62 65 * will generally be unusable by lx for timer_create.
63 66 */
64 67
65 68 static int ltos_clock[] = {
66 69 CLOCK_REALTIME, /* LX_CLOCK_REALTIME */
67 70 CLOCK_HIGHRES, /* LX_CLOCK_MONOTONIC */
68 71 CLOCK_PROCESS_CPUTIME_ID, /* LX_CLOCK_PROCESS_CPUTIME_ID */
69 72 CLOCK_THREAD_CPUTIME_ID, /* LX_CLOCK_THREAD_CPUTIME_ID */
70 73 CLOCK_HIGHRES, /* LX_CLOCK_MONOTONIC_RAW */
71 74 CLOCK_REALTIME, /* LX_CLOCK_REALTIME_COARSE */
72 75 CLOCK_HIGHRES /* LX_CLOCK_MONOTONIC_COARSE */
73 76 };
74 77
75 78 /*
76 79 * Since the Illumos CLOCK_HIGHRES clock requires elevated privs, which can
77 80 * lead to a DOS, we use the only other option (CLOCK_REALTIME) when given
78 81 * LX_CLOCK_MONOTONIC.
79 82 */
80 83 static int ltos_timer[] = {
81 84 CLOCK_REALTIME,
82 85 CLOCK_REALTIME,
83 86 CLOCK_THREAD_CPUTIME_ID, /* XXX thread, not process but fails */
84 87 CLOCK_THREAD_CPUTIME_ID,
85 88 CLOCK_REALTIME,
86 89 CLOCK_REALTIME,
87 90 CLOCK_REALTIME
88 91 };
89 92
90 93 #define LX_CLOCK_MAX (sizeof (ltos_clock) / sizeof (ltos_clock[0]))
91 94 #define LX_TIMER_MAX (sizeof (ltos_timer) / sizeof (ltos_timer[0]))
92 95
93 96 #define LX_SIGEV_PAD_SIZE ((64 - \
94 97 (sizeof (int) * 2 + sizeof (union sigval))) / sizeof (int))
95 98
96 99 typedef struct {
97 100 union sigval lx_sigev_value; /* same layout for both */
98 101 int lx_sigev_signo;
99 102 int lx_sigev_notify;
↓ open down ↓ |
61 lines elided |
↑ open up ↑ |
100 103 union {
101 104 int lx_pad[LX_SIGEV_PAD_SIZE];
102 105 int lx_tid;
103 106 struct {
104 107 void (*lx_notify_function)(union sigval);
105 108 void *lx_notify_attribute;
106 109 } lx_sigev_thread;
107 110 } lx_sigev_un;
108 111 } lx_sigevent_t;
109 112
113 +#define lx_sigev_notify_attributes lx_sigev_un.lx_sigev_thread.lx_notify_attribute
114 +
110 115 /* sigevent sigev_notify conversion table */
111 116 static int ltos_sigev[] = {
112 117 SIGEV_SIGNAL,
113 118 SIGEV_NONE,
114 119 SIGEV_THREAD,
115 120 0, /* Linux skips event 3 */
116 - SIGEV_THREAD /* the Linux SIGEV_THREAD_ID */
121 + SIGEV_THREAD /* Linux SIGEV_THREAD_ID -- see lx_sigev_thread_id() */
117 122 };
118 123
119 -#define LX_SIGEV_MAX (sizeof (ltos_sigev) / sizeof (ltos_sigev[0]))
124 +#define LX_SIGEV_MAX (sizeof (ltos_sigev) / sizeof (ltos_sigev[0]))
125 +#define LX_SIGEV_THREAD_ID 4
120 126
121 127 long
122 128 lx_clock_nanosleep(int clock, int flags, struct timespec *rqtp,
123 129 struct timespec *rmtp)
124 130 {
125 131 int ret = 0;
126 132 int err;
127 133 struct timespec rqt, rmt;
128 134
129 135 if (clock < 0 || clock >= LX_CLOCK_MAX)
130 136 return (-EINVAL);
131 137
132 138 if (uucopy(rqtp, &rqt, sizeof (struct timespec)) < 0)
133 139 return (-EFAULT);
134 140
135 141 /* the TIMER_RELTIME and TIMER_ABSTIME flags are the same on Linux */
136 142 if ((err = clock_nanosleep(ltos_clock[clock], flags, &rqt, &rmt))
137 143 != 0) {
138 144 if (err != EINTR)
139 145 return (-err);
140 146 ret = -EINTR;
141 147 /*
142 148 * We fall through in case we have to pass back the remaining
143 149 * time.
144 150 */
145 151 }
146 152
147 153 /*
148 154 * Only copy values to rmtp if the timer is TIMER_RELTIME and rmtp is
149 155 * non-NULL.
150 156 */
151 157 if (((flags & TIMER_RELTIME) == TIMER_RELTIME) && (rmtp != NULL) &&
152 158 (uucopy(&rmt, rmtp, sizeof (struct timespec)) < 0))
153 159 return (-EFAULT);
154 160
155 161 return (ret);
↓ open down ↓ |
26 lines elided |
↑ open up ↑ |
156 162 }
157 163
158 164 /*ARGSUSED*/
159 165 long
160 166 lx_adjtimex(void *tp)
161 167 {
162 168 return (-EPERM);
163 169 }
164 170
165 171 /*
172 + * Notification function for use with native SIGEV_THREAD in order to
173 + * emulate Linux SIGEV_THREAD_ID. Native SIGEV_THREAD is used as the
174 + * timer mechanism and B_SIGEV_THREAD_ID performs the actual event
175 + * delivery to the appropriate lx tid.
176 + */
177 +static void
178 +lx_sigev_thread_id(union sigval sival)
179 +{
180 + lx_sigevent_t *lev = (lx_sigevent_t *)sival.sival_ptr;
181 + syscall(SYS_brand, B_SIGEV_THREAD_ID, lev->lx_sigev_un.lx_tid,
182 + lev->lx_sigev_signo, lev->lx_sigev_value);
183 + free(lev);
184 +}
185 +
186 +
187 +/*
166 188 * The Illumos timer_create man page says it accepts the following clocks:
167 189 * CLOCK_REALTIME (3) wall clock
168 190 * CLOCK_VIRTUAL (1) user CPU usage clock - No Backend
169 191 * CLOCK_PROF (2) user and system CPU usage clock - No Backend
170 192 * CLOCK_HIGHRES (4) non-adjustable, high-resolution clock
171 193 * However, in reality the Illumos timer_create only accepts CLOCK_REALTIME
172 194 * and CLOCK_HIGHRES, and since we can't use CLOCK_HIGHRES in a zone, we're
173 195 * down to one clock.
174 196 */
175 197 long
176 198 lx_timer_create(int clock, struct sigevent *lx_sevp, timer_t *tid)
177 199 {
178 200 lx_sigevent_t lev;
179 201 struct sigevent sev;
180 202
181 203 if (clock < 0 || clock >= LX_TIMER_MAX)
182 204 return (-EINVAL);
183 205
184 206 /* We have to convert the Linux sigevent layout to the Illumos layout */
185 207 if (uucopy(lx_sevp, &lev, sizeof (lev)) < 0)
↓ open down ↓ |
10 lines elided |
↑ open up ↑ |
186 208 return (-EFAULT);
187 209
188 210 if (lev.lx_sigev_notify < 0 || lev.lx_sigev_notify > LX_SIGEV_MAX)
189 211 return (-EINVAL);
190 212
191 213 sev.sigev_notify = ltos_sigev[lev.lx_sigev_notify];
192 214 sev.sigev_signo = ltos_signo[lev.lx_sigev_signo];
193 215 sev.sigev_value = lev.lx_sigev_value;
194 216
195 217 /*
196 - * The sigevent sigev_notify_function and sigev_notify_attributes
197 - * members are not used by timer_create, so no conversion is needed.
218 + * Assume all Linux libc implementations map SIGEV_THREAD to
219 + * SIGEV_THREAD_ID and ignore passed-in attributes.
198 220 */
221 + sev.sigev_notify_attributes = NULL;
199 222
223 + if (lev.lx_sigev_notify == LX_SIGEV_THREAD_ID) {
224 + /*
225 + * Pass the original lx sigevent_t to the native
226 + * notify function so that it may pass it to the lx
227 + * helper thread.
228 + */
229 + lx_sigevent_t *lev_copy = malloc(sizeof (lx_sigevent_t));
230 + if (lev_copy == NULL)
231 + return (-ENOMEM);
232 +
233 + if (uucopy(&lev, lev_copy, sizeof (lx_sigevent_t)) < 0)
234 + return (-EFAULT);
235 +
236 + sev.sigev_notify_function = lx_sigev_thread_id;
237 + sev.sigev_value.sival_ptr = lev_copy;
238 + }
239 +
200 240 return ((timer_create(ltos_timer[clock], &sev, tid) < 0) ? -errno : 0);
201 241 }
202 242
203 243 long
204 244 lx_timer_settime(timer_t tid, int flags, struct itimerspec *new_val,
205 245 struct itimerspec *old_val)
206 246 {
207 247 return ((timer_settime(tid, flags, new_val, old_val) < 0) ? -errno : 0);
208 248 }
209 249
210 250 long
211 251 lx_timer_gettime(timer_t tid, struct itimerspec *val)
212 252 {
213 253 return ((timer_gettime(tid, val) < 0) ? -errno : 0);
214 254 }
215 255
216 256 long
217 257 lx_timer_getoverrun(timer_t tid)
218 258 {
219 259 int val;
220 260
221 261 val = timer_getoverrun(tid);
222 262 return ((val < 0) ? -errno : val);
223 263 }
224 264
225 265 long
226 266 lx_timer_delete(timer_t tid)
227 267 {
228 268 return ((timer_delete(tid) < 0) ? -errno : 0);
229 269 }
↓ open down ↓ |
20 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX