dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / lib / libcpc / common / obsoleted.c
blobe528b409d99da4731cb5aa6b78de9c1b1d7f8c95
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
20 * CDDL HEADER END
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <sys/syscall.h>
32 #include <stdlib.h>
33 #include <stdio.h>
34 #include <unistd.h>
35 #include <errno.h>
36 #include <string.h>
37 #include <strings.h>
38 #include <stdarg.h>
39 #include <signal.h>
40 #include <libintl.h>
41 #include <dirent.h>
42 #include <sys/cpc_impl.h>
44 #include "libcpc.h"
45 #include "libcpc_impl.h"
48 * CPC library handle for use by CPCv1 implementation.
50 cpc_t *__cpc = NULL;
51 mutex_t __cpc_lock; /* protects __cpc handle */
52 int __cpc_v1_cpuver; /* CPU version in use by CPCv1 client */
54 uint32_t __cpc_v1_pes[2]; /* last bound %pes values */
56 int
57 __cpc_init(void)
59 const char *fn = "__cpc_init";
60 extern cpc_t *__cpc; /* CPC handle for obsolete clients to share */
62 (void) mutex_lock(&__cpc_lock);
63 if (__cpc == NULL && (__cpc = cpc_open(CPC_VER_CURRENT)) == NULL) {
64 __cpc_error(fn, dgettext(TEXT_DOMAIN,
65 "Couldn't open CPC library handle\n"));
66 (void) mutex_unlock(&__cpc_lock);
67 return (-1);
69 (void) mutex_unlock(&__cpc_lock);
71 return (0);
74 int
75 cpc_bind_event(cpc_event_t *this, int flags)
77 cpc_set_t *set;
78 cpc_request_t *rp;
79 int ret;
81 if (this == NULL) {
82 (void) cpc_rele();
83 return (0);
86 if (__cpc_init() != 0) {
87 errno = ENXIO;
88 return (-1);
92 * The cpuver and control fields of the cpc_event_t must be saved off
93 * for later. The user may call cpc_take_sample(), expecting these to
94 * be copied into a different cpc_event_t struct by the kernel. We have
95 * to fake that behavior for CPCv1 clients.
97 __cpc_v1_cpuver = this->ce_cpuver;
98 __cpc_v1_pes[0] = this->ce_pes[0];
99 __cpc_v1_pes[1] = this->ce_pes[1];
101 if ((set = __cpc_eventtoset(__cpc, this, flags)) == NULL) {
102 errno = EINVAL;
103 return (-1);
107 * Convert flags to CPC2.
109 if (flags & CPC_BIND_EMT_OVF) {
110 for (rp = set->cs_request; rp != NULL; rp = rp->cr_next)
111 rp->cr_flags |= CPC_OVF_NOTIFY_EMT;
112 flags &= ~CPC_BIND_EMT_OVF;
115 ret = cpc_bind_curlwp(__cpc, set, flags);
117 (void) cpc_set_destroy(__cpc, set);
119 return (ret);
123 cpc_take_sample(cpc_event_t *this)
125 this->ce_cpuver = __cpc_v1_cpuver;
126 this->ce_pes[0] = __cpc_v1_pes[0];
127 this->ce_pes[1] = __cpc_v1_pes[1];
129 return (syscall(SYS_cpc, CPC_SAMPLE, -1, this->ce_pic, &this->ce_hrt,
130 &CPC_TICKREG(this), 0));
134 cpc_count_usr_events(int enable)
136 return (syscall(SYS_cpc, CPC_USR_EVENTS, -1, enable, 0));
140 cpc_count_sys_events(int enable)
142 return (syscall(SYS_cpc, CPC_SYS_EVENTS, -1, enable, 0));
146 cpc_rele(void)
148 return (syscall(SYS_cpc, CPC_RELE, -1, NULL, 0));
152 * See if the system call is working and installed.
154 * We invoke the system call with nonsense arguments - if it's
155 * there and working correctly, it will return EINVAL.
157 * (This avoids the user getting a SIGSYS core dump when they attempt
158 * to bind on older hardware)
161 cpc_access(void)
163 void (*handler)(int);
164 int error = 0;
165 const char fn[] = "access";
167 handler = signal(SIGSYS, SIG_IGN);
168 if (syscall(SYS_cpc, -1, -1, NULL, 0) == -1 &&
169 errno != EINVAL)
170 error = errno;
171 (void) signal(SIGSYS, handler);
173 switch (error) {
174 case EAGAIN:
175 __cpc_error(fn, dgettext(TEXT_DOMAIN, "Another process may be "
176 "sampling system-wide CPU statistics\n"));
177 break;
178 case ENOSYS:
179 __cpc_error(fn,
180 dgettext(TEXT_DOMAIN, "CPU performance counters "
181 "are inaccessible on this machine\n"));
182 break;
183 default:
184 __cpc_error(fn, "%s\n", strerror(errno));
185 break;
186 case 0:
187 return (0);
190 errno = error;
191 return (-1);
195 * To look at the system-wide counters, we have to open the
196 * 'shared' device. Once that device is open, no further contexts
197 * can be installed (though one open is needed per CPU)
200 cpc_shared_open(void)
202 const char driver[] = CPUDRV_SHARED;
204 return (open(driver, O_RDWR));
207 void
208 cpc_shared_close(int fd)
210 (void) cpc_shared_rele(fd);
211 (void) close(fd);
215 cpc_shared_bind_event(int fd, cpc_event_t *this, int flags)
217 extern cpc_t *__cpc;
218 cpc_set_t *set;
219 int ret;
220 char *packed_set;
221 size_t packsize;
222 int subcode;
223 __cpc_args_t cpc_args;
225 if (this == NULL) {
226 (void) cpc_shared_rele(fd);
227 return (0);
228 } else if (flags != 0) {
229 errno = EINVAL;
230 return (-1);
233 if (__cpc_init() != 0) {
234 errno = ENXIO;
235 return (-1);
238 if ((set = __cpc_eventtoset(__cpc, this, flags)) == NULL) {
239 errno = EINVAL;
240 return (-1);
243 __cpc_v1_cpuver = this->ce_cpuver;
245 if ((packed_set = __cpc_pack_set(set, flags, &packsize)) == NULL) {
246 errno = ENOMEM;
247 return (-1);
250 cpc_args.udata1 = packed_set;
251 cpc_args.udata2 = (void *)packsize;
252 cpc_args.udata3 = (void *)&subcode;
254 ret = ioctl(fd, CPCIO_BIND, &cpc_args);
256 free(packed_set);
257 (void) cpc_set_destroy(__cpc, set);
259 return (ret);
263 cpc_shared_take_sample(int fd, cpc_event_t *this)
265 __cpc_args_t args;
267 args.udata1 = this->ce_pic;
268 args.udata2 = &this->ce_hrt;
269 args.udata3 = &CPC_TICKREG(this);
271 this->ce_cpuver = __cpc_v1_cpuver;
273 return (ioctl(fd, CPCIO_SAMPLE, &args));
277 cpc_shared_rele(int fd)
279 return (ioctl(fd, CPCIO_RELE, 0));
283 cpc_pctx_bind_event(pctx_t *pctx, id_t lwpid, cpc_event_t *event, int flags)
285 cpc_set_t *set;
286 int ret;
288 if (event == NULL)
289 return (cpc_pctx_rele(pctx, lwpid));
291 if (__cpc_init() != 0) {
292 errno = ENXIO;
293 return (-1);
296 else if (flags != 0) {
297 errno = EINVAL;
298 return (-1);
301 if ((set = __cpc_eventtoset(__cpc, event, flags)) == NULL) {
302 errno = EINVAL;
303 return (-1);
307 * The cpuver and control fields of the cpc_event_t must be saved off
308 * for later. The user may call cpc_take_sample(), expecting these to
309 * be copied into a different cpc_event_t struct by the kernel. We have
310 * to fake that behavior for CPCv1 clients.
312 __cpc_v1_cpuver = event->ce_cpuver;
314 ret = cpc_bind_pctx(__cpc, pctx, lwpid, set, 0);
316 (void) cpc_set_destroy(__cpc, set);
318 return (ret);
322 cpc_pctx_take_sample(pctx_t *pctx, id_t lwpid, cpc_event_t *event)
324 event->ce_cpuver = __cpc_v1_cpuver;
326 return (__pctx_cpc(pctx, __cpc, CPC_SAMPLE, lwpid, event->ce_pic,
327 &event->ce_hrt, &CPC_TICKREG(event), CPC1_BUFSIZE));
331 * Given a process context and an lwpid, mark the CPU performance
332 * counter context as invalid.
335 cpc_pctx_invalidate(pctx_t *pctx, id_t lwpid)
337 return (__pctx_cpc(pctx, __cpc, CPC_INVALIDATE, lwpid, 0, 0, 0, 0));
341 * Given a process context and an lwpid, remove all our
342 * hardware context from it.
345 cpc_pctx_rele(pctx_t *pctx, id_t lwpid)
347 return (__pctx_cpc(pctx, __cpc, CPC_RELE, lwpid, 0, 0, 0, 0));
350 static cpc_errfn_t *__cpc_uerrfn;
352 /*PRINTFLIKE2*/
353 void
354 __cpc_error(const char *fn, const char *fmt, ...)
356 va_list ap;
358 va_start(ap, fmt);
359 if (__cpc_uerrfn)
360 __cpc_uerrfn(fn, fmt, ap);
361 else {
362 (void) fprintf(stderr, "libcpc: %s: ", fn);
363 (void) vfprintf(stderr, fmt, ap);
365 va_end(ap);
368 void
369 cpc_seterrfn(cpc_errfn_t *errfn)
371 __cpc_uerrfn = errfn;
375 * cpc_version() is only for CPC1 clients.
377 uint_t __cpc_workver = CPC_VER_1;
379 uint_t
380 cpc_version(uint_t ver)
382 __cpc_workver = CPC_VER_1;
384 switch (ver) {
385 case CPC_VER_NONE:
386 case CPC_VER_CURRENT:
387 return (CPC_VER_CURRENT);
388 case CPC_VER_1:
390 * As long as the client is using cpc_version() at all, it is
391 * a CPCv1 client. We still allow CPCv1 clients to compile on
392 * CPCv2 systems.
394 return (CPC_VER_1);
397 return (CPC_VER_NONE);