8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
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:
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;
|
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
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 <sys/syscall.h>
29
30 #include <errno.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <time.h>
34 #include <unistd.h>
35 #include <sys/resource.h>
36 #include <sys/lx_misc.h>
37 #include <sys/lx_syscall.h>
38 #include <lx_signum.h>
39
40 /*
41 * Translating from the Linux clock types to the Illumos types is a bit of a
42 * mess.
43 *
44 * Linux uses different values for it clock identifiers, so we have to do basic
45 * translations between the two. Thankfully, both Linux and Illumos implement
46 * the same POSIX SUSv3 clock types, so the semantics should be identical.
47 *
48 * However, CLOCK_REALTIME and CLOCK_HIGHRES (CLOCK_MONOTONIC) are the only two
49 * clock backends currently implemented on Illumos. Functions in the kernel
50 * that use the CLOCK_BACKEND macro will return an error for any clock type
51 * that does not exist in the clock_backend array. These functions are
52 * clock_settime, clock_gettime, clock_getres and timer_create.
53 *
54 * For reference, the kernel's clock_backend array looks like this:
100 typedef struct {
101 union sigval lx_sigev_value; /* same layout for both */
102 int lx_sigev_signo;
103 int lx_sigev_notify;
104 union {
105 int lx_pad[LX_SIGEV_PAD_SIZE];
106 int lx_tid;
107 struct {
108 void (*lx_notify_function)(union sigval);
109 void *lx_notify_attribute;
110 } lx_sigev_thread;
111 } lx_sigev_un;
112 } lx_sigevent_t;
113
114 /* sigevent sigev_notify conversion table */
115 static int ltos_sigev[] = {
116 SIGEV_SIGNAL,
117 SIGEV_NONE,
118 SIGEV_THREAD,
119 0, /* Linux skips event 3 */
120 SIGEV_THREAD /* Linux SIGEV_THREAD_ID -- see lx_sigev_thread_id() */
121 };
122
123 #define LX_SIGEV_MAX (sizeof (ltos_sigev) / sizeof (ltos_sigev[0]))
124 #define LX_SIGEV_THREAD_ID 4
125
126 long
127 lx_clock_nanosleep(int clock, int flags, struct timespec *rqtp,
128 struct timespec *rmtp)
129 {
130 int ret = 0;
131 int err;
132 struct timespec rqt, rmt;
133
134 if (clock < 0 || clock >= LX_CLOCK_MAX)
135 return (-EINVAL);
136
137 if (uucopy(rqtp, &rqt, sizeof (struct timespec)) < 0)
138 return (-EFAULT);
139
140 /* the TIMER_RELTIME and TIMER_ABSTIME flags are the same on Linux */
141 if ((err = clock_nanosleep(ltos_clock[clock], flags, &rqt, &rmt))
142 != 0) {
143 if (err != EINTR)
144 return (-err);
151
152 /*
153 * Only copy values to rmtp if the timer is TIMER_RELTIME and rmtp is
154 * non-NULL.
155 */
156 if (((flags & TIMER_RELTIME) == TIMER_RELTIME) && (rmtp != NULL) &&
157 (uucopy(&rmt, rmtp, sizeof (struct timespec)) < 0))
158 return (-EFAULT);
159
160 return (ret);
161 }
162
163 /*ARGSUSED*/
164 long
165 lx_adjtimex(void *tp)
166 {
167 return (-EPERM);
168 }
169
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 /*
187 * The Illumos timer_create man page says it accepts the following clocks:
188 * CLOCK_REALTIME (3) wall clock
189 * CLOCK_VIRTUAL (1) user CPU usage clock - No Backend
190 * CLOCK_PROF (2) user and system CPU usage clock - No Backend
191 * CLOCK_HIGHRES (4) non-adjustable, high-resolution clock
192 * However, in reality the Illumos timer_create only accepts CLOCK_REALTIME
193 * and CLOCK_HIGHRES, and since we can't use CLOCK_HIGHRES in a zone, we're
194 * down to one clock.
195 */
196 long
197 lx_timer_create(int clock, struct sigevent *lx_sevp, timer_t *tid)
198 {
199 lx_sigevent_t lev;
200 struct sigevent sev;
201
202 if (clock < 0 || clock >= LX_TIMER_MAX)
203 return (-EINVAL);
204
205 /* We have to convert the Linux sigevent layout to the Illumos layout */
206 if (uucopy(lx_sevp, &lev, sizeof (lev)) < 0)
207 return (-EFAULT);
208
209 if (lev.lx_sigev_notify < 0 || lev.lx_sigev_notify > LX_SIGEV_MAX)
210 return (-EINVAL);
211
212 sev.sigev_notify = ltos_sigev[lev.lx_sigev_notify];
213 sev.sigev_signo = ltos_signo[lev.lx_sigev_signo];
214 sev.sigev_value = lev.lx_sigev_value;
215
216 /*
217 * Assume all Linux libc implementations map SIGEV_THREAD to
218 * SIGEV_THREAD_ID and ignore passed-in attributes.
219 */
220 sev.sigev_notify_attributes = NULL;
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
267 return ((timer_create(ltos_timer[clock], &sev, tid) < 0) ? -errno : 0);
268 }
269
270 long
271 lx_timer_settime(timer_t tid, int flags, struct itimerspec *new_val,
272 struct itimerspec *old_val)
273 {
274 return ((timer_settime(tid, flags, new_val, old_val) < 0) ? -errno : 0);
275 }
276
277 long
278 lx_timer_gettime(timer_t tid, struct itimerspec *val)
279 {
280 return ((timer_gettime(tid, val) < 0) ? -errno : 0);
281 }
282
283 long
284 lx_timer_getoverrun(timer_t tid)
285 {
286 int val;
|