1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 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 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include "lint.h" 28 #include <time.h> 29 #include <sys/types.h> 30 #include <stdlib.h> 31 #include <string.h> 32 #include <errno.h> 33 #include "sigev_thread.h" 34 35 /* 36 * System call wrappers found elsewhere in libc (common/sys/__clock_timer.s). 37 */ 38 extern int __clock_getres(clockid_t, timespec_t *); 39 extern int __clock_gettime(clockid_t, timespec_t *); 40 extern int __clock_settime(clockid_t, const timespec_t *); 41 extern hrtime_t __gethrtime(void); 42 extern int __timer_create(clockid_t, struct sigevent *, timer_t *); 43 extern int __timer_delete(timer_t); 44 extern int __timer_getoverrun(timer_t); 45 extern int __timer_gettime(timer_t, itimerspec_t *); 46 extern int __timer_settime(timer_t, int, const itimerspec_t *, itimerspec_t *); 47 48 /* 49 * Array of pointers to tcd's, indexed by timer id. 50 * No more than 'timer_max' timers can be created by any process. 51 */ 52 int timer_max = 0; 53 thread_communication_data_t **timer_tcd; 54 static pthread_once_t timer_once = PTHREAD_ONCE_INIT; 55 56 static void 57 timer_init(void) 58 { 59 timer_max = (int)_sysconf(_SC_TIMER_MAX); 60 timer_tcd = malloc(timer_max * sizeof (*timer_tcd)); 61 (void) memset(timer_tcd, 0, timer_max * sizeof (*timer_tcd)); 62 } 63 64 int 65 clock_getres(clockid_t clock_id, timespec_t *res) 66 { 67 return (__clock_getres(clock_id, res)); 68 } 69 70 int 71 clock_gettime(clockid_t clock_id, timespec_t *tp) 72 { 73 return (__clock_gettime(clock_id, tp)); 74 } 75 76 int 77 clock_settime(clockid_t clock_id, const timespec_t *tp) 78 { 79 return (__clock_settime(clock_id, tp)); 80 } 81 82 hrtime_t 83 gethrtime(void) 84 { 85 return (__gethrtime()); 86 } 87 88 int 89 timer_create(clockid_t clock_id, struct sigevent *sigevp, timer_t *timerid) 90 { 91 struct sigevent sigevent; 92 port_notify_t port_notify; 93 thread_communication_data_t *tcdp; 94 int sigev_thread = 0; 95 int rc; 96 97 (void) pthread_once(&timer_once, timer_init); 98 99 if (sigevp != NULL && 100 sigevp->sigev_notify == SIGEV_THREAD && 101 sigevp->sigev_notify_function != NULL) { 102 sigev_thread = 1; 103 tcdp = setup_sigev_handler(sigevp, TIMER); 104 if (tcdp == NULL) 105 return (-1); 106 /* copy the sigevent structure so we can modify it */ 107 sigevent = *sigevp; 108 sigevp = &sigevent; 109 port_notify.portnfy_port = tcdp->tcd_port; 110 port_notify.portnfy_user = NULL; 111 sigevp->sigev_value.sival_ptr = &port_notify; 112 } 113 114 rc = __timer_create(clock_id, sigevp, timerid); 115 116 if (sigev_thread) { 117 if (rc == 0) { 118 if ((rc = launch_spawner(tcdp)) != 0) 119 (void) __timer_delete(*timerid); 120 else 121 timer_tcd[*timerid] = tcdp; 122 } 123 if (rc != 0) 124 free_sigev_handler(tcdp); 125 } 126 127 return (rc); 128 } 129 130 int 131 timer_delete(timer_t timerid) 132 { 133 int rc; 134 135 if ((rc = del_sigev_timer(timerid)) == 0) 136 return (__timer_delete(timerid)); 137 else 138 return (rc); 139 } 140 141 int 142 timer_getoverrun(timer_t timerid) 143 { 144 return (__timer_getoverrun(timerid) + sigev_timer_getoverrun(timerid)); 145 } 146 147 int 148 timer_gettime(timer_t timerid, itimerspec_t *value) 149 { 150 return (__timer_gettime(timerid, value)); 151 } 152 153 int 154 timer_settime(timer_t timerid, int flags, const itimerspec_t *value, 155 itimerspec_t *ovalue) 156 { 157 return (__timer_settime(timerid, flags, value, ovalue)); 158 } 159 160 /* 161 * Cleanup after fork1() in the child process. 162 */ 163 void 164 postfork1_child_sigev_timer(void) 165 { 166 thread_communication_data_t *tcdp; 167 int timer; 168 169 for (timer = 0; timer < timer_max; timer++) { 170 if ((tcdp = timer_tcd[timer]) != NULL) { 171 timer_tcd[timer] = NULL; 172 tcd_teardown(tcdp); 173 } 174 } 175 } 176