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 */ 38extern int __clock_getres(clockid_t, timespec_t *); 39extern int __clock_gettime(clockid_t, timespec_t *); 40extern int __clock_settime(clockid_t, const timespec_t *); 41extern int __timer_create(clockid_t, struct sigevent *, timer_t *); 42extern int __timer_delete(timer_t); 43extern int __timer_getoverrun(timer_t); 44extern int __timer_gettime(timer_t, itimerspec_t *); 45extern 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 */ 51int timer_max = 0; 52thread_communication_data_t **timer_tcd; 53static pthread_once_t timer_once = PTHREAD_ONCE_INIT; 54 55static void 56timer_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 63int 64clock_getres(clockid_t clock_id, timespec_t *res) 65{ 66 return (__clock_getres(clock_id, res)); 67} 68 69int 70clock_gettime(clockid_t clock_id, timespec_t *tp) 71{ 72 return (__clock_gettime(clock_id, tp)); 73} 74 75int 76clock_settime(clockid_t clock_id, const timespec_t *tp) 77{ 78 return (__clock_settime(clock_id, tp)); 79} 80 81int 82timer_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 123int 124timer_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 134int 135timer_getoverrun(timer_t timerid) 136{ 137 return (__timer_getoverrun(timerid) + sigev_timer_getoverrun(timerid)); 138} 139 140int 141timer_gettime(timer_t timerid, itimerspec_t *value) 142{ 143 return (__timer_gettime(timerid, value)); 144} 145 146int 147timer_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 */ 156void 157postfork1_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