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.
90 #define LX_CLOCK_MAX (sizeof (ltos_clock) / sizeof (ltos_clock[0]))
91 #define LX_TIMER_MAX (sizeof (ltos_timer) / sizeof (ltos_timer[0]))
92
93 #define LX_SIGEV_PAD_SIZE ((64 - \
94 (sizeof (int) * 2 + sizeof (union sigval))) / sizeof (int))
95
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 <sys/resource.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.
93 #define LX_CLOCK_MAX (sizeof (ltos_clock) / sizeof (ltos_clock[0]))
94 #define LX_TIMER_MAX (sizeof (ltos_timer) / sizeof (ltos_timer[0]))
95
96 #define LX_SIGEV_PAD_SIZE ((64 - \
97 (sizeof (int) * 2 + sizeof (union sigval))) / sizeof (int))
98
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 #define lx_sigev_notify_attributes lx_sigev_un.lx_sigev_thread.lx_notify_attribute
114
115 /* sigevent sigev_notify conversion table */
116 static int ltos_sigev[] = {
117 SIGEV_SIGNAL,
118 SIGEV_NONE,
119 SIGEV_THREAD,
120 0, /* Linux skips event 3 */
121 SIGEV_THREAD /* Linux SIGEV_THREAD_ID -- see lx_sigev_thread_id() */
122 };
123
124 #define LX_SIGEV_MAX (sizeof (ltos_sigev) / sizeof (ltos_sigev[0]))
125 #define LX_SIGEV_THREAD_ID 4
126
127 long
128 lx_clock_nanosleep(int clock, int flags, struct timespec *rqtp,
129 struct timespec *rmtp)
130 {
131 int ret = 0;
132 int err;
133 struct timespec rqt, rmt;
134
135 if (clock < 0 || clock >= LX_CLOCK_MAX)
136 return (-EINVAL);
137
138 if (uucopy(rqtp, &rqt, sizeof (struct timespec)) < 0)
139 return (-EFAULT);
140
141 /* the TIMER_RELTIME and TIMER_ABSTIME flags are the same on Linux */
142 if ((err = clock_nanosleep(ltos_clock[clock], flags, &rqt, &rmt))
143 != 0) {
144 if (err != EINTR)
145 return (-err);
152
153 /*
154 * Only copy values to rmtp if the timer is TIMER_RELTIME and rmtp is
155 * non-NULL.
156 */
157 if (((flags & TIMER_RELTIME) == TIMER_RELTIME) && (rmtp != NULL) &&
158 (uucopy(&rmt, rmtp, sizeof (struct timespec)) < 0))
159 return (-EFAULT);
160
161 return (ret);
162 }
163
164 /*ARGSUSED*/
165 long
166 lx_adjtimex(void *tp)
167 {
168 return (-EPERM);
169 }
170
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 /*
188 * The Illumos timer_create man page says it accepts the following clocks:
189 * CLOCK_REALTIME (3) wall clock
190 * CLOCK_VIRTUAL (1) user CPU usage clock - No Backend
191 * CLOCK_PROF (2) user and system CPU usage clock - No Backend
192 * CLOCK_HIGHRES (4) non-adjustable, high-resolution clock
193 * However, in reality the Illumos timer_create only accepts CLOCK_REALTIME
194 * and CLOCK_HIGHRES, and since we can't use CLOCK_HIGHRES in a zone, we're
195 * down to one clock.
196 */
197 long
198 lx_timer_create(int clock, struct sigevent *lx_sevp, timer_t *tid)
199 {
200 lx_sigevent_t lev;
201 struct sigevent sev;
202
203 if (clock < 0 || clock >= LX_TIMER_MAX)
204 return (-EINVAL);
205
206 /* We have to convert the Linux sigevent layout to the Illumos layout */
207 if (uucopy(lx_sevp, &lev, sizeof (lev)) < 0)
208 return (-EFAULT);
209
210 if (lev.lx_sigev_notify < 0 || lev.lx_sigev_notify > LX_SIGEV_MAX)
211 return (-EINVAL);
212
213 sev.sigev_notify = ltos_sigev[lev.lx_sigev_notify];
214 sev.sigev_signo = ltos_signo[lev.lx_sigev_signo];
215 sev.sigev_value = lev.lx_sigev_value;
216
217 /*
218 * Assume all Linux libc implementations map SIGEV_THREAD to
219 * SIGEV_THREAD_ID and ignore passed-in attributes.
220 */
221 sev.sigev_notify_attributes = NULL;
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
240 return ((timer_create(ltos_timer[clock], &sev, tid) < 0) ? -errno : 0);
241 }
242
243 long
244 lx_timer_settime(timer_t tid, int flags, struct itimerspec *new_val,
245 struct itimerspec *old_val)
246 {
247 return ((timer_settime(tid, flags, new_val, old_val) < 0) ? -errno : 0);
248 }
249
250 long
251 lx_timer_gettime(timer_t tid, struct itimerspec *val)
252 {
253 return ((timer_gettime(tid, val) < 0) ? -errno : 0);
254 }
255
256 long
257 lx_timer_getoverrun(timer_t tid)
258 {
259 int val;
|