Print this page
OS-5804 lxbrand needs support for CLOCK_*_CPUTIME_ID timers
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/uts/common/brand/lx/syscall/lx_timer.c
+++ new/usr/src/uts/common/brand/lx/syscall/lx_timer.c
1 1 /*
2 2 * This file and its contents are supplied under the terms of the
|
↓ open down ↓ |
2 lines elided |
↑ open up ↑ |
3 3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 4 * You may only use this file in accordance with the terms of version
5 5 * 1.0 of the CDDL.
6 6 *
7 7 * A full copy of the text of the CDDL should have accompanied this
8 8 * source. A copy of the CDDL is also available via the Internet at
9 9 * http://www.illumos.org/license/CDDL.
10 10 */
11 11
12 12 /*
13 - * Copyright 2016 Joyent, Inc.
13 + * Copyright 2020 Joyent, Inc.
14 14 */
15 15
16 16 /*
17 17 * The illumos kernel provides two clock backends: CLOCK_REALTIME, the
18 18 * adjustable system wall clock; and CLOCK_HIGHRES, the monotonically
19 19 * increasing time source that is not subject to drift or adjustment. By
20 20 * contrast, the Linux kernel is furnished with an overabundance of narrowly
21 21 * differentiated clock types.
22 22 *
23 - * Fortunately, most of the commonly used Linux clock types are either similar
24 - * enough to the native clock backends that they can be directly mapped, or
25 - * represent queries to the per-process and per-LWP microstate counters.
23 + * Fortunately, most of the commonly used Linux clock types are similar
24 + * enough to the native clock backends that they can be directly mapped.
26 25 *
26 + * Unfortunately, while CLOCK_{THREAD,PROCESS}_CPUTIME_ID are *somewhat*
27 + * implemented in the main illumos kernel as itimers (see setitimer(2)), we
28 + * would need to entirely bringup of CLOCK_{THREAD,PROCESS}_CPUTIME_ID to
29 + * implement timer_create() and friends. For now, we opt to map it to
30 + * CLOCK_HIGHRES for timer_create() and friends, but continue to emulate
31 + * more-accurate queries to per-process or per-LWP microstate accounting for
32 + * getres, gettime, or settime.
33 + *
27 34 * CLOCK_BOOTTIME is identical to CLOCK_MONOTONIC, except that it takes into
28 35 * account time that the system is suspended. Since that is uninteresting to
29 36 * us, we treat it the same.
30 37 */
31 38
32 39 #include <sys/time.h>
33 40 #include <sys/systm.h>
34 41 #include <sys/cmn_err.h>
35 42 #include <sys/brand.h>
36 43 #include <sys/lx_brand.h>
37 44 #include <sys/lx_impl.h>
38 45 #include <lx_signum.h>
39 46
40 47 /*
41 48 * From "uts/common/os/timer.c":
42 49 */
43 50 extern int clock_settime(clockid_t, timespec_t *);
44 51 extern int clock_gettime(clockid_t, timespec_t *);
45 52 extern int clock_getres(clockid_t, timespec_t *);
46 53 extern int nanosleep(timespec_t *, timespec_t *);
47 54
48 55
49 56 static int lx_emul_clock_getres(clockid_t, timespec_t *);
50 57 static int lx_emul_clock_gettime(clockid_t, timespec_t *);
51 58 static int lx_emul_clock_settime(clockid_t, timespec_t *);
52 59
53 60 typedef struct lx_clock_backend {
54 61 clockid_t lclk_ntv_id;
55 62 int (*lclk_clock_getres)(clockid_t, timespec_t *);
56 63 int (*lclk_clock_gettime)(clockid_t, timespec_t *);
57 64 int (*lclk_clock_settime)(clockid_t, timespec_t *);
58 65 } lx_clock_backend_t;
59 66
60 67 /*
61 68 * NOTE: The Linux man pages state this structure is obsolete and is
62 69 * unsupported, so it is declared here for sizing purposes only.
63 70 */
64 71 struct lx_timezone {
65 72 int tz_minuteswest; /* minutes W of Greenwich */
66 73 int tz_dsttime; /* type of dst correction */
67 74 };
68 75
69 76 /*
70 77 * Use the native clock_* system call implementation, but with a translated
71 78 * clock identifier:
72 79 */
73 80 #define NATIVE(ntv_id) \
74 81 { ntv_id, clock_getres, clock_gettime, clock_settime }
75 82
|
↓ open down ↓ |
39 lines elided |
↑ open up ↑ |
76 83 /*
77 84 * This backend is not supported, so we provide an emulation handler:
78 85 */
79 86 #define EMUL(ntv_id) \
80 87 { ntv_id, lx_emul_clock_getres, lx_emul_clock_gettime, \
81 88 lx_emul_clock_settime }
82 89
83 90 static lx_clock_backend_t lx_clock_backends[] = {
84 91 NATIVE(CLOCK_REALTIME), /* LX_CLOCK_REALTIME */
85 92 NATIVE(CLOCK_HIGHRES), /* LX_CLOCK_MONOTONIC */
86 - EMUL(CLOCK_PROCESS_CPUTIME_ID), /* LX_CLOCK_PROCESS_CPUTIME_ID */
87 - EMUL(CLOCK_THREAD_CPUTIME_ID), /* LX_CLOCK_THREAD_CPUTIME_ID */
93 + EMUL(CLOCK_HIGHRES), /* LX_CLOCK_PROCESS_CPUTIME_ID */
94 + EMUL(CLOCK_HIGHRES), /* LX_CLOCK_THREAD_CPUTIME_ID */
88 95 NATIVE(CLOCK_HIGHRES), /* LX_CLOCK_MONOTONIC_RAW */
89 96 NATIVE(CLOCK_REALTIME), /* LX_CLOCK_REALTIME_COARSE */
90 97 NATIVE(CLOCK_HIGHRES), /* LX_CLOCK_MONOTONIC_COARSE */
91 98 NATIVE(CLOCK_HIGHRES) /* LX_CLOCK_BOOTTIME */
92 99 };
93 100
94 101 #define LX_CLOCK_MAX \
95 102 (sizeof (lx_clock_backends) / sizeof (lx_clock_backends[0]))
96 103 #define LX_CLOCK_BACKEND(clk) (((clk) < LX_CLOCK_MAX && (clk) >= 0) ? \
97 104 &lx_clock_backends[(clk)] : NULL)
98 105
99 106 /*
100 107 * Linux defines the size of the sigevent structure to be 64 bytes. In order
101 108 * to meet that definition, the trailing union includes a member which pads it
102 109 * out to the desired length for the given architecture.
103 110 */
104 111 #define LX_SIGEV_PAD_SIZE ((64 - \
105 112 (sizeof (int) * 2 + sizeof (union sigval))) / sizeof (int))
106 113
107 114 typedef struct {
108 115 union sigval lx_sigev_value;
109 116 int lx_sigev_signo;
110 117 int lx_sigev_notify;
111 118 union {
112 119 int lx_pad[LX_SIGEV_PAD_SIZE];
113 120 int lx_tid;
114 121 struct {
115 122 void (*lx_notify_function)(union sigval);
116 123 void *lx_notify_attribute;
117 124 } lx_sigev_thread;
118 125 } lx_sigev_un;
119 126 } lx_sigevent_t;
120 127
121 128
122 129 #ifdef _SYSCALL32_IMPL
123 130
124 131 #define LX_SIGEV32_PAD_SIZE ((64 - \
125 132 (sizeof (int) * 2 + sizeof (union sigval32))) / sizeof (int))
126 133
127 134 typedef struct {
128 135 union sigval32 lx_sigev_value;
129 136 int lx_sigev_signo;
130 137 int lx_sigev_notify;
131 138 union {
132 139 int lx_pad[LX_SIGEV32_PAD_SIZE];
133 140 int lx_tid;
134 141 struct {
135 142 caddr32_t lx_notify_function;
136 143 caddr32_t lx_notify_attribute;
137 144 } lx_sigev_thread;
138 145 } lx_sigev_un;
139 146 } lx_sigevent32_t;
140 147
141 148 #endif /* _SYSCALL32_IMPL */
142 149
143 150 #define LX_SIGEV_SIGNAL 0
144 151 #define LX_SIGEV_NONE 1
145 152 #define LX_SIGEV_THREAD 2
146 153 #define LX_SIGEV_THREAD_ID 4
147 154
148 155 /*
149 156 * Access private SIGEV_THREAD_ID callback state in itimer_t
150 157 */
151 158 #define LX_SIGEV_THREAD_ID_LPID(it) ((it)->it_cb_data[0])
152 159 #define LX_SIGEV_THREAD_ID_TID(it) ((it)->it_cb_data[1])
153 160
154 161
155 162 /* ARGSUSED */
156 163 static int
157 164 lx_emul_clock_settime(clockid_t clock, timespec_t *tp)
158 165 {
159 166 return (set_errno(EINVAL));
160 167 }
161 168
162 169 static int
163 170 lx_emul_clock_gettime(clockid_t clock, timespec_t *tp)
164 171 {
165 172 timespec_t t;
166 173
167 174 switch (clock) {
168 175 case CLOCK_PROCESS_CPUTIME_ID: {
169 176 proc_t *p = ttoproc(curthread);
170 177 hrtime_t snsecs, unsecs;
171 178
172 179 /*
173 180 * Based on getrusage() in "rusagesys.c":
174 181 */
175 182 mutex_enter(&p->p_lock);
176 183 unsecs = mstate_aggr_state(p, LMS_USER);
177 184 snsecs = mstate_aggr_state(p, LMS_SYSTEM);
178 185 mutex_exit(&p->p_lock);
179 186
180 187 hrt2ts(unsecs + snsecs, &t);
181 188 break;
182 189 }
183 190
184 191 case CLOCK_THREAD_CPUTIME_ID: {
185 192 klwp_t *lwp = ttolwp(curthread);
186 193 struct mstate *ms = &lwp->lwp_mstate;
187 194 hrtime_t snsecs, unsecs;
188 195
189 196 /*
190 197 * Based on getrusage_lwp() in "rusagesys.c":
191 198 */
192 199 unsecs = ms->ms_acct[LMS_USER];
193 200 snsecs = ms->ms_acct[LMS_SYSTEM] + ms->ms_acct[LMS_TRAP];
194 201
195 202 scalehrtime(&unsecs);
196 203 scalehrtime(&snsecs);
197 204
198 205 hrt2ts(unsecs + snsecs, &t);
199 206 break;
200 207 }
201 208
202 209 default:
203 210 return (set_errno(EINVAL));
204 211 }
205 212
206 213 #if defined(_SYSCALL32_IMPL)
207 214 if (get_udatamodel() != DATAMODEL_NATIVE) {
208 215 timespec32_t t32;
209 216
210 217 if (TIMESPEC_OVERFLOW(&t)) {
211 218 return (set_errno(EOVERFLOW));
212 219 }
213 220 TIMESPEC_TO_TIMESPEC32(&t32, &t);
214 221
215 222 if (copyout(&t32, tp, sizeof (t32)) != 0) {
216 223 return (set_errno(EFAULT));
217 224 }
218 225
219 226 return (0);
220 227 }
221 228 #endif
222 229
223 230 if (copyout(&t, tp, sizeof (t)) != 0) {
224 231 return (set_errno(EFAULT));
225 232 }
226 233
227 234 return (0);
228 235 }
229 236
230 237 static int
231 238 lx_emul_clock_getres(clockid_t clock, timespec_t *tp)
232 239 {
233 240 timespec_t t;
234 241
235 242 if (tp == NULL) {
236 243 return (0);
237 244 }
238 245
239 246 switch (clock) {
240 247 case CLOCK_PROCESS_CPUTIME_ID:
241 248 case CLOCK_THREAD_CPUTIME_ID:
242 249 /*
243 250 * These clock backends return microstate accounting values for
244 251 * the LWP or the entire process. The Linux kernel claims they
245 252 * have nanosecond resolution; so will we.
246 253 */
247 254 t.tv_sec = 0;
248 255 t.tv_nsec = 1;
249 256 break;
250 257
251 258 default:
252 259 return (set_errno(EINVAL));
253 260 }
254 261
255 262 #if defined(_SYSCALL32_IMPL)
256 263 if (get_udatamodel() != DATAMODEL_NATIVE) {
257 264 timespec32_t t32;
258 265
259 266 if (TIMESPEC_OVERFLOW(&t)) {
260 267 return (set_errno(EOVERFLOW));
261 268 }
262 269 TIMESPEC_TO_TIMESPEC32(&t32, &t);
263 270
264 271 if (copyout(&t32, tp, sizeof (t32)) != 0) {
265 272 return (set_errno(EFAULT));
266 273 }
267 274
268 275 return (0);
269 276 }
270 277 #endif
271 278
272 279 if (copyout(&t, tp, sizeof (t)) != 0) {
273 280 return (set_errno(EFAULT));
274 281 }
275 282
276 283 return (0);
277 284 }
278 285
279 286 static void
280 287 lx_clock_unsupported(int clock)
281 288 {
282 289 char buf[100];
283 290
284 291 (void) snprintf(buf, sizeof (buf), "unsupported clock: %d", clock);
285 292 lx_unsupported(buf);
286 293 }
287 294
288 295 long
289 296 lx_clock_settime(int clock, timespec_t *tp)
290 297 {
291 298 lx_clock_backend_t *backend;
292 299
293 300 if ((backend = LX_CLOCK_BACKEND(clock)) == NULL) {
294 301 lx_clock_unsupported(clock);
295 302 return (set_errno(EINVAL));
296 303 }
297 304
298 305 return (backend->lclk_clock_settime(backend->lclk_ntv_id, tp));
299 306 }
300 307
301 308 long
302 309 lx_clock_gettime(int clock, timespec_t *tp)
303 310 {
304 311 lx_clock_backend_t *backend;
305 312
306 313 if ((backend = LX_CLOCK_BACKEND(clock)) == NULL) {
307 314 lx_clock_unsupported(clock);
308 315 return (set_errno(EINVAL));
309 316 }
310 317
311 318 return (backend->lclk_clock_gettime(backend->lclk_ntv_id, tp));
312 319 }
313 320
314 321 long
315 322 lx_clock_getres(int clock, timespec_t *tp)
316 323 {
317 324 lx_clock_backend_t *backend;
318 325
319 326 if ((backend = LX_CLOCK_BACKEND(clock)) == NULL) {
320 327 lx_clock_unsupported(clock);
321 328 return (set_errno(EINVAL));
322 329 }
323 330
324 331 /*
325 332 * It is important this check is performed after the clock
326 333 * check. Both glibc and musl, in their clock_getcpuclockid(),
327 334 * use clock_getres() with a NULL tp to validate a clock
328 335 * value. Performing the tp check before the clock check could
329 336 * indicate a valid clock to libc when it shouldn't.
330 337 */
331 338 if (tp == NULL) {
332 339 return (0);
333 340 }
334 341
335 342 return (backend->lclk_clock_getres(backend->lclk_ntv_id, tp));
336 343 }
337 344
338 345 static int
339 346 lx_ltos_sigev(lx_sigevent_t *lev, struct sigevent *sev)
340 347 {
341 348 bzero(sev, sizeof (*sev));
342 349
343 350 switch (lev->lx_sigev_notify) {
344 351 case LX_SIGEV_NONE:
345 352 sev->sigev_notify = SIGEV_NONE;
346 353 break;
347 354
348 355 case LX_SIGEV_SIGNAL:
349 356 case LX_SIGEV_THREAD_ID:
350 357 sev->sigev_notify = SIGEV_SIGNAL;
351 358 break;
352 359
353 360 case LX_SIGEV_THREAD:
354 361 /*
355 362 * Just as in illumos, SIGEV_THREAD handling is performed in
356 363 * userspace with the help of SIGEV_SIGNAL/SIGEV_THREAD_ID.
357 364 *
358 365 * It's not expected to make an appearance in the syscall.
359 366 */
360 367 default:
361 368 return (EINVAL);
362 369 }
363 370
364 371 sev->sigev_signo = lx_ltos_signo(lev->lx_sigev_signo, 0);
365 372 sev->sigev_value = lev->lx_sigev_value;
366 373
367 374 /* Ensure SIGEV_SIGNAL has a valid signo to work with. */
368 375 if (sev->sigev_notify == SIGEV_SIGNAL && sev->sigev_signo == 0) {
369 376 return (EINVAL);
370 377 }
371 378 return (0);
372 379 }
373 380
374 381 static int
375 382 lx_sigev_copyin(lx_sigevent_t *userp, lx_sigevent_t *levp)
376 383 {
377 384 #ifdef _SYSCALL32_IMPL
378 385 if (get_udatamodel() != DATAMODEL_NATIVE) {
379 386 lx_sigevent32_t lev32;
380 387
381 388 if (copyin(userp, &lev32, sizeof (lev32)) != 0) {
382 389 return (EFAULT);
383 390 }
384 391 levp->lx_sigev_value.sival_int = lev32.lx_sigev_value.sival_int;
385 392 levp->lx_sigev_signo = lev32.lx_sigev_signo;
386 393 levp->lx_sigev_notify = lev32.lx_sigev_notify;
387 394 levp->lx_sigev_un.lx_tid = lev32.lx_sigev_un.lx_tid;
388 395 } else
389 396 #endif /* _SYSCALL32_IMPL */
390 397 {
391 398 if (copyin(userp, levp, sizeof (lx_sigevent_t)) != 0) {
392 399 return (EFAULT);
393 400 }
394 401 }
395 402 return (0);
396 403 }
397 404
398 405 static void
399 406 lx_sigev_thread_fire(itimer_t *it)
400 407 {
401 408 proc_t *p = it->it_proc;
402 409 pid_t lpid = (pid_t)LX_SIGEV_THREAD_ID_LPID(it);
403 410 id_t tid = (id_t)LX_SIGEV_THREAD_ID_TID(it);
404 411 lwpdir_t *ld;
405 412
406 413 ASSERT(MUTEX_HELD(&it->it_mutex));
407 414 ASSERT(it->it_pending == 0);
408 415 ASSERT(it->it_flags & IT_SIGNAL);
409 416 ASSERT(MUTEX_HELD(&p->p_lock));
410 417
411 418 ld = lwp_hash_lookup(p, tid);
412 419 if (ld != NULL) {
413 420 lx_lwp_data_t *lwpd;
414 421 kthread_t *t;
415 422
416 423 t = ld->ld_entry->le_thread;
417 424 lwpd = ttolxlwp(t);
418 425 if (lwpd != NULL && lwpd->br_pid == lpid) {
419 426 /*
420 427 * A thread matching the LX pid is still present in the
421 428 * process. Send a targeted signal as requested.
422 429 */
423 430 it->it_pending = 1;
424 431 mutex_exit(&it->it_mutex);
425 432 sigaddqa(p, t, it->it_sigq);
426 433 return;
427 434 }
428 435 }
429 436
430 437 mutex_exit(&it->it_mutex);
431 438 }
432 439
433 440 long
434 441 lx_timer_create(int clock, lx_sigevent_t *sevp, timer_t *tidp)
435 442 {
436 443 int error;
437 444 lx_sigevent_t lev;
438 445 struct sigevent sev;
439 446 clock_backend_t *backend = NULL;
440 447 proc_t *p = curproc;
441 448 itimer_t *itp;
442 449 timer_t tid;
443 450
444 451 if (clock == -2) {
445 452 /*
446 453 * A change was made to the old userspace timer emulation to
447 454 * handle this specific clock ID for MapR. It was wrongly
448 455 * mapped to CLOCK_REALTIME rather than CLOCK_THREAD_CPUTIME_ID
449 456 * which it maps to. Until the CLOCK_*_CPUTIME_ID timers can
450 457 * be emulated, the admittedly incorrect mapping will remain.
451 458 */
452 459 backend = clock_get_backend(CLOCK_REALTIME);
453 460 } else {
454 461 lx_clock_backend_t *lback = LX_CLOCK_BACKEND(clock);
455 462
456 463 if (lback != NULL) {
457 464 backend = clock_get_backend(lback->lclk_ntv_id);
458 465 }
459 466 }
460 467 if (backend == NULL) {
461 468 return (set_errno(EINVAL));
462 469 }
463 470
464 471 /* We have to convert the Linux sigevent layout to the illumos layout */
465 472 if (sevp != NULL) {
466 473 if ((error = lx_sigev_copyin(sevp, &lev)) != 0) {
467 474 return (set_errno(error));
468 475 }
469 476 if ((error = lx_ltos_sigev(&lev, &sev)) != 0) {
470 477 return (set_errno(error));
471 478 }
472 479 } else {
473 480 bzero(&sev, sizeof (sev));
474 481 sev.sigev_notify = SIGEV_SIGNAL;
475 482 sev.sigev_signo = SIGALRM;
476 483 }
477 484
478 485 if ((error = timer_setup(backend, &sev, NULL, &itp, &tid)) != 0) {
479 486 return (set_errno(error));
480 487 }
481 488
482 489 /*
483 490 * The SIGEV_THREAD_ID notification method in Linux allows the caller
484 491 * to target a specific thread to receive the signal. The IT_CALLBACK
485 492 * timer functionality is used to fulfill this need. After translating
486 493 * the LX pid to a SunOS thread ID (ensuring it exists in the current
487 494 * process), those IDs are attached to the timer along with the custom
488 495 * lx_sigev_thread_fire callback. This targets the signal notification
489 496 * properly when the timer fires.
490 497 */
491 498 if (lev.lx_sigev_notify == LX_SIGEV_THREAD_ID) {
492 499 pid_t lpid, spid;
493 500 id_t stid;
494 501
495 502 lpid = (pid_t)lev.lx_sigev_un.lx_tid;
496 503 if (lx_lpid_to_spair(lpid, &spid, &stid) != 0 ||
497 504 spid != curproc->p_pid) {
498 505 error = EINVAL;
499 506 goto err;
500 507 }
501 508
502 509 itp->it_flags |= IT_CALLBACK;
503 510 itp->it_cb_func = lx_sigev_thread_fire;
504 511 LX_SIGEV_THREAD_ID_LPID(itp) = lpid;
505 512 LX_SIGEV_THREAD_ID_TID(itp) = stid;
506 513 }
507 514
508 515 /*
509 516 * When the sigevent is not specified, its sigev_value field is
510 517 * expected to be populated with the timer ID.
511 518 */
512 519 if (sevp == NULL) {
513 520 itp->it_sigq->sq_info.si_value.sival_int = tid;
514 521 }
515 522
516 523 if (copyout(&tid, tidp, sizeof (timer_t)) != 0) {
517 524 error = EFAULT;
518 525 goto err;
519 526 }
520 527
521 528 timer_release(p, itp);
522 529 return (0);
523 530
524 531 err:
525 532 timer_delete_grabbed(p, tid, itp);
526 533 return (set_errno(error));
527 534 }
528 535
529 536 long
530 537 lx_gettimeofday(struct timeval *tvp, struct lx_timezone *tzp)
531 538 {
532 539 struct lx_timezone tz;
533 540
534 541 bzero(&tz, sizeof (tz));
535 542
536 543 /*
537 544 * We want to be similar to libc which just does a fasttrap to
538 545 * gethrestime and simply converts that result. We follow how uniqtime
539 546 * does the conversion but we can't use that code since it does some
540 547 * extra work which can cause the result to bounce around based on which
541 548 * CPU we run on.
542 549 */
543 550 if (tvp != NULL) {
544 551 struct timeval tv;
545 552 timestruc_t ts;
546 553 int usec, nsec;
547 554
548 555 gethrestime(&ts);
549 556 nsec = ts.tv_nsec;
550 557 usec = nsec + (nsec >> 2);
551 558 usec = nsec + (usec >> 1);
552 559 usec = nsec + (usec >> 2);
553 560 usec = nsec + (usec >> 4);
554 561 usec = nsec - (usec >> 3);
555 562 usec = nsec + (usec >> 2);
556 563 usec = nsec + (usec >> 3);
557 564 usec = nsec + (usec >> 4);
558 565 usec = nsec + (usec >> 1);
559 566 usec = nsec + (usec >> 6);
560 567 usec = usec >> 10;
561 568
562 569 tv.tv_sec = ts.tv_sec;
563 570 tv.tv_usec = usec;
564 571
565 572 if (get_udatamodel() == DATAMODEL_NATIVE) {
566 573 if (copyout(&tv, tvp, sizeof (tv)) != 0)
567 574 return (set_errno(EFAULT));
568 575 }
569 576 #ifdef _SYSCALL32_IMPL
570 577 else {
571 578 struct timeval32 tv32;
572 579
573 580 if (TIMEVAL_OVERFLOW(&tv))
574 581 return (set_errno(EOVERFLOW));
575 582 TIMEVAL_TO_TIMEVAL32(&tv32, &tv);
576 583
577 584 if (copyout(&tv32, tvp, sizeof (tv32)))
578 585 return (set_errno(EFAULT));
579 586 }
580 587 #endif
581 588 }
582 589
583 590 /*
584 591 * The Linux man page states use of the second parameter is obsolete,
585 592 * but gettimeofday(2) should still return EFAULT if it is set
586 593 * to a bad non-NULL pointer (sigh...)
587 594 */
588 595 if (tzp != NULL && copyout(&tz, tzp, sizeof (tz)) != 0)
589 596 return (set_errno(EFAULT));
590 597
591 598 return (0);
592 599 }
593 600
594 601 /*
595 602 * On Linux a bad buffer will set errno to EFAULT, and on Illumos the failure
596 603 * mode is documented as "undefined."
597 604 */
598 605 long
599 606 lx_time(time_t *tp)
600 607 {
601 608 timestruc_t ts;
602 609 struct timeval tv;
603 610
604 611 gethrestime(&ts);
605 612 tv.tv_sec = ts.tv_sec;
606 613 tv.tv_usec = 0;
607 614
608 615 if (get_udatamodel() == DATAMODEL_NATIVE) {
609 616 if (tp != NULL &&
610 617 copyout(&tv.tv_sec, tp, sizeof (tv.tv_sec)) != 0)
611 618 return (set_errno(EFAULT));
612 619
613 620 return (tv.tv_sec);
614 621 }
615 622 #ifdef _SYSCALL32_IMPL
616 623 else {
617 624 struct timeval32 tv32;
618 625
619 626 if (TIMEVAL_OVERFLOW(&tv))
620 627 return (set_errno(EOVERFLOW));
621 628 TIMEVAL_TO_TIMEVAL32(&tv32, &tv);
622 629
623 630 if (tp != NULL &&
624 631 copyout(&tv32.tv_sec, tp, sizeof (tv32.tv_sec)))
625 632 return (set_errno(EFAULT));
626 633
627 634 return (tv32.tv_sec);
628 635 }
629 636 #endif /* _SYSCALL32_IMPL */
630 637 /* NOTREACHED */
631 638 }
632 639
633 640 long
634 641 lx_nanosleep(timespec_t *rqtp, timespec_t *rmtp)
635 642 {
636 643 return (nanosleep(rqtp, rmtp));
637 644 }
|
↓ open down ↓ |
540 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX