9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 * Copyright 2015 Joyent, Inc.
26 */
27
28 #include <errno.h>
29 #include <string.h>
30 #include <time.h>
31 #include <sys/resource.h>
32 #include <sys/lx_misc.h>
33 #include <sys/lx_syscall.h>
34 #include <lx_signum.h>
35
36 /*
37 * Translating from the Linux clock types to the Illumos types is a bit of a
38 * mess.
39 *
40 * Linux uses different values for it clock identifiers, so we have to do basic
41 * translations between the two. Thankfully, both Linux and Illumos implement
42 * the same POSIX SUSv3 clock types, so the semantics should be identical.
43 *
44 * However, CLOCK_REALTIME and CLOCK_HIGHRES (CLOCK_MONOTONIC) are the only two
45 * clock backends currently implemented on Illumos. Functions in the kernel
46 * that use the CLOCK_BACKEND macro will return an error for any clock type
47 * that does not exist in the clock_backend array. These functions are
48 * clock_settime, clock_gettime, clock_getres and timer_create.
49 *
50 * For reference, the kernel's clock_backend array looks like this:
51 *
96 typedef struct {
97 union sigval lx_sigev_value; /* same layout for both */
98 int lx_sigev_signo;
99 int lx_sigev_notify;
100 union {
101 int lx_pad[LX_SIGEV_PAD_SIZE];
102 int lx_tid;
103 struct {
104 void (*lx_notify_function)(union sigval);
105 void *lx_notify_attribute;
106 } lx_sigev_thread;
107 } lx_sigev_un;
108 } lx_sigevent_t;
109
110 /* sigevent sigev_notify conversion table */
111 static int ltos_sigev[] = {
112 SIGEV_SIGNAL,
113 SIGEV_NONE,
114 SIGEV_THREAD,
115 0, /* Linux skips event 3 */
116 SIGEV_THREAD /* the Linux SIGEV_THREAD_ID */
117 };
118
119 #define LX_SIGEV_MAX (sizeof (ltos_sigev) / sizeof (ltos_sigev[0]))
120
121 long
122 lx_clock_nanosleep(int clock, int flags, struct timespec *rqtp,
123 struct timespec *rmtp)
124 {
125 int ret = 0;
126 int err;
127 struct timespec rqt, rmt;
128
129 if (clock < 0 || clock >= LX_CLOCK_MAX)
130 return (-EINVAL);
131
132 if (uucopy(rqtp, &rqt, sizeof (struct timespec)) < 0)
133 return (-EFAULT);
134
135 /* the TIMER_RELTIME and TIMER_ABSTIME flags are the same on Linux */
136 if ((err = clock_nanosleep(ltos_clock[clock], flags, &rqt, &rmt))
137 != 0) {
138 if (err != EINTR)
139 return (-err);
146
147 /*
148 * Only copy values to rmtp if the timer is TIMER_RELTIME and rmtp is
149 * non-NULL.
150 */
151 if (((flags & TIMER_RELTIME) == TIMER_RELTIME) && (rmtp != NULL) &&
152 (uucopy(&rmt, rmtp, sizeof (struct timespec)) < 0))
153 return (-EFAULT);
154
155 return (ret);
156 }
157
158 /*ARGSUSED*/
159 long
160 lx_adjtimex(void *tp)
161 {
162 return (-EPERM);
163 }
164
165 /*
166 * The Illumos timer_create man page says it accepts the following clocks:
167 * CLOCK_REALTIME (3) wall clock
168 * CLOCK_VIRTUAL (1) user CPU usage clock - No Backend
169 * CLOCK_PROF (2) user and system CPU usage clock - No Backend
170 * CLOCK_HIGHRES (4) non-adjustable, high-resolution clock
171 * However, in reality the Illumos timer_create only accepts CLOCK_REALTIME
172 * and CLOCK_HIGHRES, and since we can't use CLOCK_HIGHRES in a zone, we're
173 * down to one clock.
174 */
175 long
176 lx_timer_create(int clock, struct sigevent *lx_sevp, timer_t *tid)
177 {
178 lx_sigevent_t lev;
179 struct sigevent sev;
180
181 if (clock < 0 || clock >= LX_TIMER_MAX)
182 return (-EINVAL);
183
184 /* We have to convert the Linux sigevent layout to the Illumos layout */
185 if (uucopy(lx_sevp, &lev, sizeof (lev)) < 0)
186 return (-EFAULT);
187
188 if (lev.lx_sigev_notify < 0 || lev.lx_sigev_notify > LX_SIGEV_MAX)
189 return (-EINVAL);
190
191 sev.sigev_notify = ltos_sigev[lev.lx_sigev_notify];
192 sev.sigev_signo = ltos_signo[lev.lx_sigev_signo];
193 sev.sigev_value = lev.lx_sigev_value;
194
195 /*
196 * The sigevent sigev_notify_function and sigev_notify_attributes
197 * members are not used by timer_create, so no conversion is needed.
198 */
199
200 return ((timer_create(ltos_timer[clock], &sev, tid) < 0) ? -errno : 0);
201 }
202
203 long
204 lx_timer_settime(timer_t tid, int flags, struct itimerspec *new_val,
205 struct itimerspec *old_val)
206 {
207 return ((timer_settime(tid, flags, new_val, old_val) < 0) ? -errno : 0);
208 }
209
210 long
211 lx_timer_gettime(timer_t tid, struct itimerspec *val)
212 {
213 return ((timer_gettime(tid, val) < 0) ? -errno : 0);
214 }
215
216 long
217 lx_timer_getoverrun(timer_t tid)
218 {
219 int val;
|
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 * Copyright 2015 Joyent, Inc.
26 */
27
28 #include <errno.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <time.h>
32 #include <unistd.h>
33 #include <sys/resource.h>
34 #include <sys/syscall.h>
35 #include <sys/lx_misc.h>
36 #include <sys/lx_syscall.h>
37 #include <lx_signum.h>
38
39 /*
40 * Translating from the Linux clock types to the Illumos types is a bit of a
41 * mess.
42 *
43 * Linux uses different values for it clock identifiers, so we have to do basic
44 * translations between the two. Thankfully, both Linux and Illumos implement
45 * the same POSIX SUSv3 clock types, so the semantics should be identical.
46 *
47 * However, CLOCK_REALTIME and CLOCK_HIGHRES (CLOCK_MONOTONIC) are the only two
48 * clock backends currently implemented on Illumos. Functions in the kernel
49 * that use the CLOCK_BACKEND macro will return an error for any clock type
50 * that does not exist in the clock_backend array. These functions are
51 * clock_settime, clock_gettime, clock_getres and timer_create.
52 *
53 * For reference, the kernel's clock_backend array looks like this:
54 *
99 typedef struct {
100 union sigval lx_sigev_value; /* same layout for both */
101 int lx_sigev_signo;
102 int lx_sigev_notify;
103 union {
104 int lx_pad[LX_SIGEV_PAD_SIZE];
105 int lx_tid;
106 struct {
107 void (*lx_notify_function)(union sigval);
108 void *lx_notify_attribute;
109 } lx_sigev_thread;
110 } lx_sigev_un;
111 } lx_sigevent_t;
112
113 /* sigevent sigev_notify conversion table */
114 static int ltos_sigev[] = {
115 SIGEV_SIGNAL,
116 SIGEV_NONE,
117 SIGEV_THREAD,
118 0, /* Linux skips event 3 */
119 SIGEV_THREAD /* Linux SIGEV_THREAD_ID -- see lx_sigev_thread_id() */
120 };
121
122 #define LX_SIGEV_MAX (sizeof (ltos_sigev) / sizeof (ltos_sigev[0]))
123 #define LX_SIGEV_THREAD_ID 4
124
125 long
126 lx_clock_nanosleep(int clock, int flags, struct timespec *rqtp,
127 struct timespec *rmtp)
128 {
129 int ret = 0;
130 int err;
131 struct timespec rqt, rmt;
132
133 if (clock < 0 || clock >= LX_CLOCK_MAX)
134 return (-EINVAL);
135
136 if (uucopy(rqtp, &rqt, sizeof (struct timespec)) < 0)
137 return (-EFAULT);
138
139 /* the TIMER_RELTIME and TIMER_ABSTIME flags are the same on Linux */
140 if ((err = clock_nanosleep(ltos_clock[clock], flags, &rqt, &rmt))
141 != 0) {
142 if (err != EINTR)
143 return (-err);
150
151 /*
152 * Only copy values to rmtp if the timer is TIMER_RELTIME and rmtp is
153 * non-NULL.
154 */
155 if (((flags & TIMER_RELTIME) == TIMER_RELTIME) && (rmtp != NULL) &&
156 (uucopy(&rmt, rmtp, sizeof (struct timespec)) < 0))
157 return (-EFAULT);
158
159 return (ret);
160 }
161
162 /*ARGSUSED*/
163 long
164 lx_adjtimex(void *tp)
165 {
166 return (-EPERM);
167 }
168
169 /*
170 * Notification function for use with native SIGEV_THREAD in order to
171 * emulate Linux SIGEV_THREAD_ID. Native SIGEV_THREAD is used as the
172 * timer mechanism and B_SIGEV_THREAD_ID performs the actual event
173 * delivery to the appropriate lx tid.
174 */
175 static void
176 lx_sigev_thread_id(union sigval sival)
177 {
178 lx_sigevent_t *lev = (lx_sigevent_t *)sival.sival_ptr;
179 syscall(SYS_brand, B_SIGEV_THREAD_ID, lev->lx_sigev_un.lx_tid,
180 lev->lx_sigev_signo, lev->lx_sigev_value.sival_ptr);
181 free(lev);
182 }
183
184
185 /*
186 * The Illumos timer_create man page says it accepts the following clocks:
187 * CLOCK_REALTIME (3) wall clock
188 * CLOCK_VIRTUAL (1) user CPU usage clock - No Backend
189 * CLOCK_PROF (2) user and system CPU usage clock - No Backend
190 * CLOCK_HIGHRES (4) non-adjustable, high-resolution clock
191 * However, in reality the Illumos timer_create only accepts CLOCK_REALTIME
192 * and CLOCK_HIGHRES, and since we can't use CLOCK_HIGHRES in a zone, we're
193 * down to one clock.
194 */
195 long
196 lx_timer_create(int clock, struct sigevent *lx_sevp, timer_t *tid)
197 {
198 lx_sigevent_t lev;
199 struct sigevent sev;
200
201 if (clock < 0 || clock >= LX_TIMER_MAX)
202 return (-EINVAL);
203
204 /* We have to convert the Linux sigevent layout to the Illumos layout */
205 if (uucopy(lx_sevp, &lev, sizeof (lev)) < 0)
206 return (-EFAULT);
207
208 if (lev.lx_sigev_notify < 0 || lev.lx_sigev_notify > LX_SIGEV_MAX)
209 return (-EINVAL);
210
211 sev.sigev_notify = ltos_sigev[lev.lx_sigev_notify];
212 sev.sigev_signo = lx_ltos_signo(lev.lx_sigev_signo, 0);
213 sev.sigev_value = lev.lx_sigev_value;
214
215 /*
216 * The signal number is meaningless in SIGEV_NONE, Linux
217 * accepts any value. We convert invalid signals to 0 so other
218 * parts of lx signal handling don't break.
219 */
220 if ((sev.sigev_notify != SIGEV_NONE) && (sev.sigev_signo == 0))
221 return (-EINVAL);
222
223 /*
224 * Assume all Linux libc implementations map SIGEV_THREAD to
225 * SIGEV_THREAD_ID and ignore passed-in attributes.
226 */
227 sev.sigev_notify_attributes = NULL;
228
229 if (lev.lx_sigev_notify == LX_SIGEV_THREAD_ID) {
230 pid_t caller_pid = getpid();
231 pid_t target_pid;
232 lwpid_t ignore;
233 lx_sigevent_t *lev_copy;
234
235 if (lx_lpid_to_spair(lev.lx_sigev_un.lx_tid,
236 &target_pid, &ignore) != 0)
237 return (-EINVAL);
238
239 /*
240 * The caller of SIGEV_THREAD_ID must be in the same
241 * process as the target thread.
242 */
243 if (caller_pid != target_pid)
244 return (-EINVAL);
245
246 /*
247 * Pass the original lx sigevent_t to the native
248 * notify function so that it may pass it to the lx
249 * helper thread. It is the responsibility of
250 * lx_sigev_thread_id() to free lev_copy after the
251 * information is relayed to lx.
252 *
253 * If the calling process is forked without an exec
254 * after this copy but before the timer fires then
255 * lev_copy will leak in the child. This is acceptable
256 * given the rarity of this event, the miniscule
257 * amount leaked, and the fact that the memory is
258 * reclaimed when the proc dies. It is firmly in the
259 * land of "good enough".
260 */
261 lev_copy = malloc(sizeof (lx_sigevent_t));
262 if (lev_copy == NULL)
263 return (-ENOMEM);
264
265 if (uucopy(&lev, lev_copy, sizeof (lx_sigevent_t)) < 0) {
266 free(lev_copy);
267 return (-EFAULT);
268 }
269
270 sev.sigev_notify_function = lx_sigev_thread_id;
271 sev.sigev_value.sival_ptr = lev_copy;
272 }
273
274 return ((timer_create(ltos_timer[clock], &sev, tid) < 0) ? -errno : 0);
275 }
276
277 long
278 lx_timer_settime(timer_t tid, int flags, struct itimerspec *new_val,
279 struct itimerspec *old_val)
280 {
281 return ((timer_settime(tid, flags, new_val, old_val) < 0) ? -errno : 0);
282 }
283
284 long
285 lx_timer_gettime(timer_t tid, struct itimerspec *val)
286 {
287 return ((timer_gettime(tid, val) < 0) ? -errno : 0);
288 }
289
290 long
291 lx_timer_getoverrun(timer_t tid)
292 {
293 int val;
|