1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright 2021 Oxide Computer Company 14 */ 15 16 /* 17 * This clock backend implements basic support for the CLOCK_PROCESS_CPUTIME_ID 18 * clock. This clock is weakly defined by POSIX as "The identifier of the 19 * CPU-time clock associated with the process making a clock() or timer*() 20 * function call". We interpret that as including LMS_USER, LMS_SYSTEM, and 21 * LMS_TRAP microstates. This is similar to what we do in proc(5) for the 22 * lwpstatus_t and the prstatus_t. 23 * 24 * At this time, we only provide the ability to read the current time (e.g. 25 * through a call to clock_gettime(3C)). There is never a case where being able 26 * to set the time makes sense today and even if so, the privileges required for 27 * that are circumspect. Today, we do not support the ability to create interval 28 * timers based on this backend (e.g. timer_create(3C) and timer_settime(3C)). 29 * However, there is no reason that couldn't be added. 30 * 31 * To implement this, we leverage the existing microstate aggregation time that 32 * is done in /proc. 33 */ 34 35 #include <sys/timer.h> 36 #include <sys/cyclic.h> 37 #include <sys/msacct.h> 38 39 static clock_backend_t clock_process; 40 41 static int 42 clock_process_settime(timespec_t *ts) 43 { 44 return (EINVAL); 45 } 46 47 static int 48 clock_process_gettime(timespec_t *ts) 49 { 50 hrtime_t hrt; 51 proc_t *p = curproc; 52 53 /* 54 * mstate_aggr_state() automatically includes LMS_TRAP when we ask for 55 * LMS_SYSTEM below. 56 */ 57 mutex_enter(&p->p_lock); 58 hrt = mstate_aggr_state(p, LMS_USER); 59 hrt += mstate_aggr_state(p, LMS_SYSTEM); 60 mutex_exit(&p->p_lock); 61 62 hrt2ts(hrt, ts); 63 64 return (0); 65 } 66 67 /* 68 * See the discussion in clock_thread_getres() for the why of using 69 * cyclic_getres() here. 70 */ 71 static int 72 clock_process_getres(timespec_t *ts) 73 { 74 hrt2ts(cyclic_getres(), (timestruc_t *)ts); 75 76 return (0); 77 } 78 79 static int 80 clock_process_timer_create(itimer_t *it, void (*fire)(itimer_t *)) 81 { 82 return (EINVAL); 83 } 84 85 static int 86 clock_process_timer_settime(itimer_t *it, int flags, 87 const struct itimerspec *when) 88 { 89 return (EINVAL); 90 } 91 92 static int 93 clock_process_timer_gettime(itimer_t *it, struct itimerspec *when) 94 { 95 return (EINVAL); 96 } 97 98 static int 99 clock_process_timer_delete(itimer_t *it) 100 { 101 return (EINVAL); 102 } 103 104 static void 105 clock_process_timer_lwpbind(itimer_t *it) 106 { 107 } 108 109 void 110 clock_process_init(void) 111 { 112 /* 113 * While this clock backend doesn't support notifications right now, we 114 * still fill out the default for what it would be. 115 */ 116 clock_process.clk_default.sigev_signo = SIGALRM; 117 clock_process.clk_default.sigev_notify = SIGEV_SIGNAL; 118 clock_process.clk_default.sigev_value.sival_ptr = NULL; 119 120 clock_process.clk_clock_settime = clock_process_settime; 121 clock_process.clk_clock_gettime = clock_process_gettime; 122 clock_process.clk_clock_getres = clock_process_getres; 123 clock_process.clk_timer_create = clock_process_timer_create; 124 clock_process.clk_timer_settime = clock_process_timer_settime; 125 clock_process.clk_timer_gettime = clock_process_timer_gettime; 126 clock_process.clk_timer_delete = clock_process_timer_delete; 127 clock_process.clk_timer_lwpbind = clock_process_timer_lwpbind; 128 129 clock_add_backend(CLOCK_PROCESS_CPUTIME_ID, &clock_process); 130 } 131