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 int __timer_create(clockid_t, struct sigevent *, timer_t *); 42 extern int __timer_delete(timer_t); 43 extern int __timer_getoverrun(timer_t); 44 extern int __timer_gettime(timer_t, itimerspec_t *); 45 extern int __timer_settime(timer_t, int, const itimerspec_t *, itimerspec_t *); 46 47 /* 48 * Array of pointers to tcd's, indexed by timer id. 49 * No more than 'timer_max' timers can be created by any process. 50 */ 51 int timer_max = 0; 52 thread_communication_data_t **timer_tcd; 53 static pthread_once_t timer_once = PTHREAD_ONCE_INIT; 54 55 static void 56 timer_init(void) 57 { 58 timer_max = (int)_sysconf(_SC_TIMER_MAX); 59 timer_tcd = malloc(timer_max * sizeof (*timer_tcd)); 60 (void) memset(timer_tcd, 0, timer_max * sizeof (*timer_tcd)); 61 } 62 63 int 64 clock_getres(clockid_t clock_id, timespec_t *res) 65 { 66 return (__clock_getres(clock_id, res)); 67 } 68 69 int 70 clock_gettime(clockid_t clock_id, timespec_t *tp) 71 { 72 return (__clock_gettime(clock_id, tp)); 73 } 74 75 int 76 clock_settime(clockid_t clock_id, const timespec_t *tp) 77 { 78 return (__clock_settime(clock_id, tp)); 79 } 80 81 int 82 timer_create(clockid_t clock_id, struct sigevent *sigevp, timer_t *timerid) 83 { 84 struct sigevent sigevent; 85 port_notify_t port_notify; 86 thread_communication_data_t *tcdp; 87 int sigev_thread = 0; 88 int rc; 89 90 (void) pthread_once(&timer_once, timer_init); 91 92 if (sigevp != NULL && 93 sigevp->sigev_notify == SIGEV_THREAD && 94 sigevp->sigev_notify_function != NULL) { 95 sigev_thread = 1; 96 tcdp = setup_sigev_handler(sigevp, TIMER); 97 if (tcdp == NULL) 98 return (-1); 99 /* copy the sigevent structure so we can modify it */ 100 sigevent = *sigevp; 101 sigevp = &sigevent; 102 port_notify.portnfy_port = tcdp->tcd_port; 103 port_notify.portnfy_user = NULL; 104 sigevp->sigev_value.sival_ptr = &port_notify; 105 } 106 107 rc = __timer_create(clock_id, sigevp, timerid); 108 109 if (sigev_thread) { 110 if (rc == 0) { 111 if ((rc = launch_spawner(tcdp)) != 0) 112 (void) __timer_delete(*timerid); 113 else 114 timer_tcd[*timerid] = tcdp; 115 } 116 if (rc != 0) 117 free_sigev_handler(tcdp); 118 } 119 120 return (rc); 121 } 122 123 int 124 timer_delete(timer_t timerid) 125 { 126 int rc; 127 128 if ((rc = del_sigev_timer(timerid)) == 0) 129 return (__timer_delete(timerid)); 130 else 131 return (rc); 132 } 133 134 int 135 timer_getoverrun(timer_t timerid) 136 { 137 return (__timer_getoverrun(timerid) + sigev_timer_getoverrun(timerid)); 138 } 139 140 int 141 timer_gettime(timer_t timerid, itimerspec_t *value) 142 { 143 return (__timer_gettime(timerid, value)); 144 } 145 146 int 147 timer_settime(timer_t timerid, int flags, const itimerspec_t *value, 148 itimerspec_t *ovalue) 149 { 150 return (__timer_settime(timerid, flags, value, ovalue)); 151 } 152 153 /* 154 * Cleanup after fork1() in the child process. 155 */ 156 void 157 postfork1_child_sigev_timer(void) 158 { 159 thread_communication_data_t *tcdp; 160 int timer; 161 162 for (timer = 0; timer < timer_max; timer++) { 163 if ((tcdp = timer_tcd[timer]) != NULL) { 164 timer_tcd[timer] = NULL; 165 tcd_teardown(tcdp); 166 } 167 } 168 } 169