17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 57c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 67c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 77c478bd9Sstevel@tonic-gate * with the License. 87c478bd9Sstevel@tonic-gate * 97c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 107c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 117c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 127c478bd9Sstevel@tonic-gate * and limitations under the License. 137c478bd9Sstevel@tonic-gate * 147c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 157c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 167c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 177c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 187c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 197c478bd9Sstevel@tonic-gate * 207c478bd9Sstevel@tonic-gate * CDDL HEADER END 217c478bd9Sstevel@tonic-gate */ 227c478bd9Sstevel@tonic-gate /* 23*1a6fa3a5Srab * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 287c478bd9Sstevel@tonic-gate 297c478bd9Sstevel@tonic-gate #include <sys/types.h> 307c478bd9Sstevel@tonic-gate #include <sys/stat.h> 317c478bd9Sstevel@tonic-gate #include <sys/syscall.h> 327c478bd9Sstevel@tonic-gate #include <stdlib.h> 337c478bd9Sstevel@tonic-gate #include <stdio.h> 347c478bd9Sstevel@tonic-gate #include <unistd.h> 357c478bd9Sstevel@tonic-gate #include <errno.h> 367c478bd9Sstevel@tonic-gate #include <string.h> 377c478bd9Sstevel@tonic-gate #include <strings.h> 387c478bd9Sstevel@tonic-gate #include <stdarg.h> 397c478bd9Sstevel@tonic-gate #include <signal.h> 407c478bd9Sstevel@tonic-gate #include <libintl.h> 417c478bd9Sstevel@tonic-gate #include <dirent.h> 427c478bd9Sstevel@tonic-gate #include <sys/cpc_impl.h> 437c478bd9Sstevel@tonic-gate 447c478bd9Sstevel@tonic-gate #include "libcpc.h" 457c478bd9Sstevel@tonic-gate #include "libcpc_impl.h" 467c478bd9Sstevel@tonic-gate 477c478bd9Sstevel@tonic-gate /* 487c478bd9Sstevel@tonic-gate * CPC library handle for use by CPCv1 implementation. 497c478bd9Sstevel@tonic-gate */ 507c478bd9Sstevel@tonic-gate cpc_t *__cpc = NULL; 517c478bd9Sstevel@tonic-gate mutex_t __cpc_lock; /* protects __cpc handle */ 527c478bd9Sstevel@tonic-gate int __cpc_v1_cpuver; /* CPU version in use by CPCv1 client */ 537c478bd9Sstevel@tonic-gate 547c478bd9Sstevel@tonic-gate #ifdef __sparc 557c478bd9Sstevel@tonic-gate uint64_t __cpc_v1_pcr; /* last bound %pcr value */ 567c478bd9Sstevel@tonic-gate #else 577c478bd9Sstevel@tonic-gate uint32_t __cpc_v1_pes[2]; /* last bound %pes values */ 587c478bd9Sstevel@tonic-gate #endif /* __sparc */ 597c478bd9Sstevel@tonic-gate 607c478bd9Sstevel@tonic-gate int 617c478bd9Sstevel@tonic-gate __cpc_init(void) 627c478bd9Sstevel@tonic-gate { 637c478bd9Sstevel@tonic-gate const char *fn = "__cpc_init"; 647c478bd9Sstevel@tonic-gate extern cpc_t *__cpc; /* CPC handle for obsolete clients to share */ 657c478bd9Sstevel@tonic-gate 667c478bd9Sstevel@tonic-gate (void) mutex_lock(&__cpc_lock); 677c478bd9Sstevel@tonic-gate if (__cpc == NULL && (__cpc = cpc_open(CPC_VER_CURRENT)) == NULL) { 687c478bd9Sstevel@tonic-gate __cpc_error(fn, dgettext(TEXT_DOMAIN, 697c478bd9Sstevel@tonic-gate "Couldn't open CPC library handle\n")); 707c478bd9Sstevel@tonic-gate (void) mutex_unlock(&__cpc_lock); 717c478bd9Sstevel@tonic-gate return (-1); 727c478bd9Sstevel@tonic-gate } 737c478bd9Sstevel@tonic-gate (void) mutex_unlock(&__cpc_lock); 747c478bd9Sstevel@tonic-gate 757c478bd9Sstevel@tonic-gate return (0); 767c478bd9Sstevel@tonic-gate } 777c478bd9Sstevel@tonic-gate 787c478bd9Sstevel@tonic-gate int 797c478bd9Sstevel@tonic-gate cpc_bind_event(cpc_event_t *this, int flags) 807c478bd9Sstevel@tonic-gate { 817c478bd9Sstevel@tonic-gate cpc_set_t *set; 827c478bd9Sstevel@tonic-gate cpc_request_t *rp; 837c478bd9Sstevel@tonic-gate int ret; 847c478bd9Sstevel@tonic-gate 857c478bd9Sstevel@tonic-gate if (this == NULL) { 867c478bd9Sstevel@tonic-gate (void) cpc_rele(); 877c478bd9Sstevel@tonic-gate return (0); 887c478bd9Sstevel@tonic-gate } 897c478bd9Sstevel@tonic-gate 907c478bd9Sstevel@tonic-gate if (__cpc_init() != 0) { 917c478bd9Sstevel@tonic-gate errno = ENXIO; 927c478bd9Sstevel@tonic-gate return (-1); 937c478bd9Sstevel@tonic-gate } 947c478bd9Sstevel@tonic-gate 957c478bd9Sstevel@tonic-gate /* 967c478bd9Sstevel@tonic-gate * The cpuver and control fields of the cpc_event_t must be saved off 977c478bd9Sstevel@tonic-gate * for later. The user may call cpc_take_sample(), expecting these to 987c478bd9Sstevel@tonic-gate * be copied into a different cpc_event_t struct by the kernel. We have 997c478bd9Sstevel@tonic-gate * to fake that behavior for CPCv1 clients. 1007c478bd9Sstevel@tonic-gate */ 1017c478bd9Sstevel@tonic-gate __cpc_v1_cpuver = this->ce_cpuver; 1027c478bd9Sstevel@tonic-gate #ifdef __sparc 1037c478bd9Sstevel@tonic-gate __cpc_v1_pcr = this->ce_pcr; 1047c478bd9Sstevel@tonic-gate #else 1057c478bd9Sstevel@tonic-gate __cpc_v1_pes[0] = this->ce_pes[0]; 1067c478bd9Sstevel@tonic-gate __cpc_v1_pes[1] = this->ce_pes[1]; 1077c478bd9Sstevel@tonic-gate #endif /* __sparc */ 1087c478bd9Sstevel@tonic-gate 1097c478bd9Sstevel@tonic-gate if ((set = __cpc_eventtoset(__cpc, this, flags)) == NULL) { 1107c478bd9Sstevel@tonic-gate errno = EINVAL; 1117c478bd9Sstevel@tonic-gate return (-1); 1127c478bd9Sstevel@tonic-gate } 1137c478bd9Sstevel@tonic-gate 1147c478bd9Sstevel@tonic-gate /* 1157c478bd9Sstevel@tonic-gate * Convert flags to CPC2. 1167c478bd9Sstevel@tonic-gate */ 1177c478bd9Sstevel@tonic-gate if (flags & CPC_BIND_EMT_OVF) { 1187c478bd9Sstevel@tonic-gate for (rp = set->cs_request; rp != NULL; rp = rp->cr_next) 1197c478bd9Sstevel@tonic-gate rp->cr_flags |= CPC_OVF_NOTIFY_EMT; 1207c478bd9Sstevel@tonic-gate flags &= ~CPC_BIND_EMT_OVF; 1217c478bd9Sstevel@tonic-gate } 1227c478bd9Sstevel@tonic-gate 1237c478bd9Sstevel@tonic-gate ret = cpc_bind_curlwp(__cpc, set, flags); 1247c478bd9Sstevel@tonic-gate 1257c478bd9Sstevel@tonic-gate (void) cpc_set_destroy(__cpc, set); 1267c478bd9Sstevel@tonic-gate 1277c478bd9Sstevel@tonic-gate return (ret); 1287c478bd9Sstevel@tonic-gate } 1297c478bd9Sstevel@tonic-gate 1307c478bd9Sstevel@tonic-gate int 1317c478bd9Sstevel@tonic-gate cpc_take_sample(cpc_event_t *this) 1327c478bd9Sstevel@tonic-gate { 1337c478bd9Sstevel@tonic-gate this->ce_cpuver = __cpc_v1_cpuver; 1347c478bd9Sstevel@tonic-gate #ifdef __sparc 1357c478bd9Sstevel@tonic-gate this->ce_pcr = __cpc_v1_pcr; 1367c478bd9Sstevel@tonic-gate #else 1377c478bd9Sstevel@tonic-gate this->ce_pes[0] = __cpc_v1_pes[0]; 1387c478bd9Sstevel@tonic-gate this->ce_pes[1] = __cpc_v1_pes[1]; 1397c478bd9Sstevel@tonic-gate #endif /* __sparc */ 1407c478bd9Sstevel@tonic-gate 1417c478bd9Sstevel@tonic-gate return (syscall(SYS_cpc, CPC_SAMPLE, -1, this->ce_pic, &this->ce_hrt, 1427c478bd9Sstevel@tonic-gate &CPC_TICKREG(this), 0)); 1437c478bd9Sstevel@tonic-gate } 1447c478bd9Sstevel@tonic-gate 1457c478bd9Sstevel@tonic-gate int 1467c478bd9Sstevel@tonic-gate cpc_count_usr_events(int enable) 1477c478bd9Sstevel@tonic-gate { 148*1a6fa3a5Srab return (syscall(SYS_cpc, CPC_USR_EVENTS, -1, enable, 0)); 1497c478bd9Sstevel@tonic-gate } 1507c478bd9Sstevel@tonic-gate 1517c478bd9Sstevel@tonic-gate int 1527c478bd9Sstevel@tonic-gate cpc_count_sys_events(int enable) 1537c478bd9Sstevel@tonic-gate { 154*1a6fa3a5Srab return (syscall(SYS_cpc, CPC_SYS_EVENTS, -1, enable, 0)); 1557c478bd9Sstevel@tonic-gate } 1567c478bd9Sstevel@tonic-gate 1577c478bd9Sstevel@tonic-gate int 1587c478bd9Sstevel@tonic-gate cpc_rele(void) 1597c478bd9Sstevel@tonic-gate { 1607c478bd9Sstevel@tonic-gate return (syscall(SYS_cpc, CPC_RELE, -1, NULL, 0)); 1617c478bd9Sstevel@tonic-gate } 1627c478bd9Sstevel@tonic-gate 1637c478bd9Sstevel@tonic-gate /* 1647c478bd9Sstevel@tonic-gate * See if the system call is working and installed. 1657c478bd9Sstevel@tonic-gate * 1667c478bd9Sstevel@tonic-gate * We invoke the system call with nonsense arguments - if it's 1677c478bd9Sstevel@tonic-gate * there and working correctly, it will return EINVAL. 1687c478bd9Sstevel@tonic-gate * 1697c478bd9Sstevel@tonic-gate * (This avoids the user getting a SIGSYS core dump when they attempt 1707c478bd9Sstevel@tonic-gate * to bind on older hardware) 1717c478bd9Sstevel@tonic-gate */ 1727c478bd9Sstevel@tonic-gate int 1737c478bd9Sstevel@tonic-gate cpc_access(void) 1747c478bd9Sstevel@tonic-gate { 1757c478bd9Sstevel@tonic-gate void (*handler)(int); 1767c478bd9Sstevel@tonic-gate int error = 0; 1777c478bd9Sstevel@tonic-gate const char fn[] = "access"; 1787c478bd9Sstevel@tonic-gate 1797c478bd9Sstevel@tonic-gate handler = signal(SIGSYS, SIG_IGN); 1807c478bd9Sstevel@tonic-gate if (syscall(SYS_cpc, -1, -1, NULL, 0) == -1 && 1817c478bd9Sstevel@tonic-gate errno != EINVAL) 1827c478bd9Sstevel@tonic-gate error = errno; 1837c478bd9Sstevel@tonic-gate (void) signal(SIGSYS, handler); 1847c478bd9Sstevel@tonic-gate 1857c478bd9Sstevel@tonic-gate switch (error) { 1867c478bd9Sstevel@tonic-gate case EAGAIN: 1877c478bd9Sstevel@tonic-gate __cpc_error(fn, dgettext(TEXT_DOMAIN, "Another process may be " 1887c478bd9Sstevel@tonic-gate "sampling system-wide CPU statistics\n")); 1897c478bd9Sstevel@tonic-gate break; 1907c478bd9Sstevel@tonic-gate case ENOSYS: 1917c478bd9Sstevel@tonic-gate __cpc_error(fn, 1927c478bd9Sstevel@tonic-gate dgettext(TEXT_DOMAIN, "CPU performance counters " 1937c478bd9Sstevel@tonic-gate "are inaccessible on this machine\n")); 1947c478bd9Sstevel@tonic-gate break; 1957c478bd9Sstevel@tonic-gate default: 1967c478bd9Sstevel@tonic-gate __cpc_error(fn, "%s\n", strerror(errno)); 1977c478bd9Sstevel@tonic-gate break; 1987c478bd9Sstevel@tonic-gate case 0: 1997c478bd9Sstevel@tonic-gate return (0); 2007c478bd9Sstevel@tonic-gate } 2017c478bd9Sstevel@tonic-gate 2027c478bd9Sstevel@tonic-gate errno = error; 2037c478bd9Sstevel@tonic-gate return (-1); 2047c478bd9Sstevel@tonic-gate } 2057c478bd9Sstevel@tonic-gate 2067c478bd9Sstevel@tonic-gate /* 2077c478bd9Sstevel@tonic-gate * To look at the system-wide counters, we have to open the 2087c478bd9Sstevel@tonic-gate * 'shared' device. Once that device is open, no further contexts 2097c478bd9Sstevel@tonic-gate * can be installed (though one open is needed per CPU) 2107c478bd9Sstevel@tonic-gate */ 2117c478bd9Sstevel@tonic-gate int 2127c478bd9Sstevel@tonic-gate cpc_shared_open(void) 2137c478bd9Sstevel@tonic-gate { 2147c478bd9Sstevel@tonic-gate const char driver[] = CPUDRV_SHARED; 2157c478bd9Sstevel@tonic-gate 2167c478bd9Sstevel@tonic-gate return (open(driver, O_RDWR)); 2177c478bd9Sstevel@tonic-gate } 2187c478bd9Sstevel@tonic-gate 2197c478bd9Sstevel@tonic-gate void 2207c478bd9Sstevel@tonic-gate cpc_shared_close(int fd) 2217c478bd9Sstevel@tonic-gate { 2227c478bd9Sstevel@tonic-gate (void) cpc_shared_rele(fd); 2237c478bd9Sstevel@tonic-gate (void) close(fd); 2247c478bd9Sstevel@tonic-gate } 2257c478bd9Sstevel@tonic-gate 2267c478bd9Sstevel@tonic-gate int 2277c478bd9Sstevel@tonic-gate cpc_shared_bind_event(int fd, cpc_event_t *this, int flags) 2287c478bd9Sstevel@tonic-gate { 2297c478bd9Sstevel@tonic-gate extern cpc_t *__cpc; 2307c478bd9Sstevel@tonic-gate cpc_set_t *set; 2317c478bd9Sstevel@tonic-gate int ret; 2327c478bd9Sstevel@tonic-gate char *packed_set; 2337c478bd9Sstevel@tonic-gate size_t packsize; 2347c478bd9Sstevel@tonic-gate int subcode; 2357c478bd9Sstevel@tonic-gate __cpc_args_t cpc_args; 2367c478bd9Sstevel@tonic-gate 2377c478bd9Sstevel@tonic-gate if (this == NULL) { 2387c478bd9Sstevel@tonic-gate (void) cpc_shared_rele(fd); 2397c478bd9Sstevel@tonic-gate return (0); 2407c478bd9Sstevel@tonic-gate } else if (flags != 0) { 2417c478bd9Sstevel@tonic-gate errno = EINVAL; 2427c478bd9Sstevel@tonic-gate return (-1); 2437c478bd9Sstevel@tonic-gate } 2447c478bd9Sstevel@tonic-gate 2457c478bd9Sstevel@tonic-gate if (__cpc_init() != 0) { 2467c478bd9Sstevel@tonic-gate errno = ENXIO; 2477c478bd9Sstevel@tonic-gate return (-1); 2487c478bd9Sstevel@tonic-gate } 2497c478bd9Sstevel@tonic-gate 2507c478bd9Sstevel@tonic-gate if ((set = __cpc_eventtoset(__cpc, this, flags)) == NULL) { 2517c478bd9Sstevel@tonic-gate errno = EINVAL; 2527c478bd9Sstevel@tonic-gate return (-1); 2537c478bd9Sstevel@tonic-gate } 2547c478bd9Sstevel@tonic-gate 2557c478bd9Sstevel@tonic-gate __cpc_v1_cpuver = this->ce_cpuver; 2567c478bd9Sstevel@tonic-gate 2577c478bd9Sstevel@tonic-gate if ((packed_set = __cpc_pack_set(set, flags, &packsize)) == NULL) { 2587c478bd9Sstevel@tonic-gate errno = ENOMEM; 2597c478bd9Sstevel@tonic-gate return (-1); 2607c478bd9Sstevel@tonic-gate } 2617c478bd9Sstevel@tonic-gate 2627c478bd9Sstevel@tonic-gate cpc_args.udata1 = packed_set; 2637c478bd9Sstevel@tonic-gate cpc_args.udata2 = (void *)packsize; 2647c478bd9Sstevel@tonic-gate cpc_args.udata3 = (void *)&subcode; 2657c478bd9Sstevel@tonic-gate 2667c478bd9Sstevel@tonic-gate ret = ioctl(fd, CPCIO_BIND, &cpc_args); 2677c478bd9Sstevel@tonic-gate 2687c478bd9Sstevel@tonic-gate free(packed_set); 2697c478bd9Sstevel@tonic-gate (void) cpc_set_destroy(__cpc, set); 2707c478bd9Sstevel@tonic-gate 2717c478bd9Sstevel@tonic-gate return (ret); 2727c478bd9Sstevel@tonic-gate } 2737c478bd9Sstevel@tonic-gate 2747c478bd9Sstevel@tonic-gate int 2757c478bd9Sstevel@tonic-gate cpc_shared_take_sample(int fd, cpc_event_t *this) 2767c478bd9Sstevel@tonic-gate { 2777c478bd9Sstevel@tonic-gate __cpc_args_t args; 2787c478bd9Sstevel@tonic-gate 2797c478bd9Sstevel@tonic-gate args.udata1 = this->ce_pic; 2807c478bd9Sstevel@tonic-gate args.udata2 = &this->ce_hrt; 2817c478bd9Sstevel@tonic-gate args.udata3 = &CPC_TICKREG(this); 2827c478bd9Sstevel@tonic-gate 2837c478bd9Sstevel@tonic-gate this->ce_cpuver = __cpc_v1_cpuver; 2847c478bd9Sstevel@tonic-gate 2857c478bd9Sstevel@tonic-gate return (ioctl(fd, CPCIO_SAMPLE, &args)); 2867c478bd9Sstevel@tonic-gate } 2877c478bd9Sstevel@tonic-gate 2887c478bd9Sstevel@tonic-gate int 2897c478bd9Sstevel@tonic-gate cpc_shared_rele(int fd) 2907c478bd9Sstevel@tonic-gate { 2917c478bd9Sstevel@tonic-gate return (ioctl(fd, CPCIO_RELE, 0)); 2927c478bd9Sstevel@tonic-gate } 2937c478bd9Sstevel@tonic-gate 2947c478bd9Sstevel@tonic-gate int 2957c478bd9Sstevel@tonic-gate cpc_pctx_bind_event(pctx_t *pctx, id_t lwpid, cpc_event_t *event, int flags) 2967c478bd9Sstevel@tonic-gate { 2977c478bd9Sstevel@tonic-gate cpc_set_t *set; 2987c478bd9Sstevel@tonic-gate int ret; 2997c478bd9Sstevel@tonic-gate 3007c478bd9Sstevel@tonic-gate if (event == NULL) 3017c478bd9Sstevel@tonic-gate return (cpc_pctx_rele(pctx, lwpid)); 3027c478bd9Sstevel@tonic-gate 3037c478bd9Sstevel@tonic-gate if (__cpc_init() != 0) { 3047c478bd9Sstevel@tonic-gate errno = ENXIO; 3057c478bd9Sstevel@tonic-gate return (-1); 3067c478bd9Sstevel@tonic-gate } 3077c478bd9Sstevel@tonic-gate 3087c478bd9Sstevel@tonic-gate else if (flags != 0) { 3097c478bd9Sstevel@tonic-gate errno = EINVAL; 3107c478bd9Sstevel@tonic-gate return (-1); 3117c478bd9Sstevel@tonic-gate } 3127c478bd9Sstevel@tonic-gate 3137c478bd9Sstevel@tonic-gate if ((set = __cpc_eventtoset(__cpc, event, flags)) == NULL) { 3147c478bd9Sstevel@tonic-gate errno = EINVAL; 3157c478bd9Sstevel@tonic-gate return (-1); 3167c478bd9Sstevel@tonic-gate } 3177c478bd9Sstevel@tonic-gate 3187c478bd9Sstevel@tonic-gate /* 3197c478bd9Sstevel@tonic-gate * The cpuver and control fields of the cpc_event_t must be saved off 3207c478bd9Sstevel@tonic-gate * for later. The user may call cpc_take_sample(), expecting these to 3217c478bd9Sstevel@tonic-gate * be copied into a different cpc_event_t struct by the kernel. We have 3227c478bd9Sstevel@tonic-gate * to fake that behavior for CPCv1 clients. 3237c478bd9Sstevel@tonic-gate */ 3247c478bd9Sstevel@tonic-gate __cpc_v1_cpuver = event->ce_cpuver; 3257c478bd9Sstevel@tonic-gate 3267c478bd9Sstevel@tonic-gate ret = cpc_bind_pctx(__cpc, pctx, lwpid, set, 0); 3277c478bd9Sstevel@tonic-gate 3287c478bd9Sstevel@tonic-gate (void) cpc_set_destroy(__cpc, set); 3297c478bd9Sstevel@tonic-gate 3307c478bd9Sstevel@tonic-gate return (ret); 3317c478bd9Sstevel@tonic-gate } 3327c478bd9Sstevel@tonic-gate 3337c478bd9Sstevel@tonic-gate int 3347c478bd9Sstevel@tonic-gate cpc_pctx_take_sample(pctx_t *pctx, id_t lwpid, cpc_event_t *event) 3357c478bd9Sstevel@tonic-gate { 3367c478bd9Sstevel@tonic-gate event->ce_cpuver = __cpc_v1_cpuver; 3377c478bd9Sstevel@tonic-gate 3387c478bd9Sstevel@tonic-gate return (__pctx_cpc(pctx, __cpc, CPC_SAMPLE, lwpid, event->ce_pic, 3397c478bd9Sstevel@tonic-gate &event->ce_hrt, &CPC_TICKREG(event), CPC1_BUFSIZE)); 3407c478bd9Sstevel@tonic-gate } 3417c478bd9Sstevel@tonic-gate 3427c478bd9Sstevel@tonic-gate /* 3437c478bd9Sstevel@tonic-gate * Given a process context and an lwpid, mark the CPU performance 3447c478bd9Sstevel@tonic-gate * counter context as invalid. 3457c478bd9Sstevel@tonic-gate */ 3467c478bd9Sstevel@tonic-gate int 3477c478bd9Sstevel@tonic-gate cpc_pctx_invalidate(pctx_t *pctx, id_t lwpid) 3487c478bd9Sstevel@tonic-gate { 3497c478bd9Sstevel@tonic-gate return (__pctx_cpc(pctx, __cpc, CPC_INVALIDATE, lwpid, 0, 0, 0, 0)); 3507c478bd9Sstevel@tonic-gate } 3517c478bd9Sstevel@tonic-gate 3527c478bd9Sstevel@tonic-gate /* 3537c478bd9Sstevel@tonic-gate * Given a process context and an lwpid, remove all our 3547c478bd9Sstevel@tonic-gate * hardware context from it. 3557c478bd9Sstevel@tonic-gate */ 3567c478bd9Sstevel@tonic-gate int 3577c478bd9Sstevel@tonic-gate cpc_pctx_rele(pctx_t *pctx, id_t lwpid) 3587c478bd9Sstevel@tonic-gate { 3597c478bd9Sstevel@tonic-gate return (__pctx_cpc(pctx, __cpc, CPC_RELE, lwpid, 0, 0, 0, 0)); 3607c478bd9Sstevel@tonic-gate } 3617c478bd9Sstevel@tonic-gate 3627c478bd9Sstevel@tonic-gate static cpc_errfn_t *__cpc_uerrfn; 3637c478bd9Sstevel@tonic-gate 3647c478bd9Sstevel@tonic-gate /*PRINTFLIKE2*/ 3657c478bd9Sstevel@tonic-gate void 3667c478bd9Sstevel@tonic-gate __cpc_error(const char *fn, const char *fmt, ...) 3677c478bd9Sstevel@tonic-gate { 3687c478bd9Sstevel@tonic-gate va_list ap; 3697c478bd9Sstevel@tonic-gate 3707c478bd9Sstevel@tonic-gate va_start(ap, fmt); 3717c478bd9Sstevel@tonic-gate if (__cpc_uerrfn) 3727c478bd9Sstevel@tonic-gate __cpc_uerrfn(fn, fmt, ap); 3737c478bd9Sstevel@tonic-gate else { 3747c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "libcpc: %s: ", fn); 3757c478bd9Sstevel@tonic-gate (void) vfprintf(stderr, fmt, ap); 3767c478bd9Sstevel@tonic-gate } 3777c478bd9Sstevel@tonic-gate va_end(ap); 3787c478bd9Sstevel@tonic-gate } 3797c478bd9Sstevel@tonic-gate 3807c478bd9Sstevel@tonic-gate void 3817c478bd9Sstevel@tonic-gate cpc_seterrfn(cpc_errfn_t *errfn) 3827c478bd9Sstevel@tonic-gate { 3837c478bd9Sstevel@tonic-gate __cpc_uerrfn = errfn; 3847c478bd9Sstevel@tonic-gate } 3857c478bd9Sstevel@tonic-gate 3867c478bd9Sstevel@tonic-gate /* 3877c478bd9Sstevel@tonic-gate * cpc_version() is only for CPC1 clients. 3887c478bd9Sstevel@tonic-gate */ 3897c478bd9Sstevel@tonic-gate uint_t __cpc_workver = CPC_VER_1; 3907c478bd9Sstevel@tonic-gate 3917c478bd9Sstevel@tonic-gate uint_t 3927c478bd9Sstevel@tonic-gate cpc_version(uint_t ver) 3937c478bd9Sstevel@tonic-gate { 3947c478bd9Sstevel@tonic-gate __cpc_workver = CPC_VER_1; 3957c478bd9Sstevel@tonic-gate 3967c478bd9Sstevel@tonic-gate switch (ver) { 3977c478bd9Sstevel@tonic-gate case CPC_VER_NONE: 3987c478bd9Sstevel@tonic-gate case CPC_VER_CURRENT: 3997c478bd9Sstevel@tonic-gate return (CPC_VER_CURRENT); 4007c478bd9Sstevel@tonic-gate case CPC_VER_1: 4017c478bd9Sstevel@tonic-gate /* 4027c478bd9Sstevel@tonic-gate * As long as the client is using cpc_version() at all, it is 4037c478bd9Sstevel@tonic-gate * a CPCv1 client. We still allow CPCv1 clients to compile on 4047c478bd9Sstevel@tonic-gate * CPCv2 systems. 4057c478bd9Sstevel@tonic-gate */ 4067c478bd9Sstevel@tonic-gate return (CPC_VER_1); 4077c478bd9Sstevel@tonic-gate } 4087c478bd9Sstevel@tonic-gate 4097c478bd9Sstevel@tonic-gate return (CPC_VER_NONE); 4107c478bd9Sstevel@tonic-gate } 411