|
|
1.1 root 1: /*
2: * Mach Operating System
3: * Copyright (c) 1993,1992 Carnegie Mellon University
4: * All Rights Reserved.
5: *
6: * Permission to use, copy, modify and distribute this software and its
7: * documentation is hereby granted, provided that both the copyright
8: * notice and this permission notice appear in all copies of the
9: * software, derivative works or modified versions, and any portions
10: * thereof, and that both notices appear in supporting documentation.
11: *
12: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
13: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
15: *
16: * Carnegie Mellon requests users of this software to return to
17: *
18: * Software Distribution Coordinator or [email protected]
19: * School of Computer Science
20: * Carnegie Mellon University
21: * Pittsburgh PA 15213-3890
22: *
23: * any improvements or extensions that they make and grant Carnegie Mellon
24: * the rights to redistribute these changes.
25: */
26:
27:
28:
29: #include <mach_pcsample.h>
30:
31: #include <mach/mach_types.h> /* vm_address_t */
32: #include <mach/std_types.h> /* pointer_t */
33: #include <mach/pc_sample.h>
34: #include <kern/host.h>
35: #include <kern/thread.h>
36: #include <kern/pc_sample.h>
37:
38: #if MACH_PCSAMPLE
39:
40: #define MAX_PC_SAMPLES 512
41:
42: typedef sampled_pc_t sampled_pcs[MAX_PC_SAMPLES];
43:
44: int pc_sampling_enabled = 0;
45: decl_simple_lock_data(, pc_sampling_lock) /* lock for enabling */
46:
47: void take_pc_sample(
48: register thread_t t,
49: register sample_control_t *cp,
50: sampled_pc_flavor_t flavor)
51: {
52: vm_offset_t pc;
53: struct sampled_pc *sample;
54:
55: pc = interrupted_pc(t);
56: cp->seqno++;
57: sample = &((sampled_pc_t *)cp->buffer)[cp->seqno % MAX_PC_SAMPLES];
58: sample->id = (natural_t)t;
59: sample->pc = pc;
60: sample->sampletype = flavor;
61: }
62:
63: kern_return_t
64: thread_enable_pc_sampling(
65: thread_t thread,
66: int *tickp,
67: sampled_pc_flavor_t flavors)
68: {
69: vm_offset_t buf;
70: extern int tick;
71:
72: if (thread == THREAD_NULL) {
73: return KERN_INVALID_ARGUMENT;
74: }
75: if (thread->pc_sample.buffer == 0) {
76: buf = (vm_offset_t) kalloc(sizeof (sampled_pcs));
77: if (buf == 0) {
78: printf("thread_enable_pc_sampling: kalloc failed\n");
79: return KERN_INVALID_ARGUMENT;
80: }
81: thread->pc_sample.buffer = buf;
82: thread->pc_sample.seqno = 0;
83: }
84: *tickp = tick;
85: thread->pc_sample.sampletypes = flavors;
86: return KERN_SUCCESS;
87: }
88:
89: kern_return_t
90: task_enable_pc_sampling(
91: task_t task,
92: int *tickp,
93: sampled_pc_flavor_t flavors)
94: {
95: vm_offset_t buf;
96: extern int tick;
97:
98: if (task == TASK_NULL) {
99: return KERN_INVALID_ARGUMENT;
100: }
101: if (task->pc_sample.buffer == 0) {
102: buf = (vm_offset_t) kalloc(sizeof (sampled_pcs));
103: if (buf == 0) {
104: printf("task_enable_pc_sampling: kalloc failed\n");
105: return KERN_INVALID_ARGUMENT;
106: }
107: task->pc_sample.buffer = buf;
108: task->pc_sample.seqno = 0;
109: }
110: *tickp = tick;
111: task->pc_sample.sampletypes = flavors;
112: return KERN_SUCCESS;
113: }
114:
115: kern_return_t
116: thread_disable_pc_sampling(
117: thread_t thread,
118: int *samplecntp)
119: {
120: vm_offset_t buf;
121:
122: if (thread == THREAD_NULL) {
123: return KERN_INVALID_ARGUMENT;
124: }
125: if ((buf = thread->pc_sample.buffer) != 0)
126: kfree(buf, sizeof (sampled_pcs));
127: thread->pc_sample.buffer = (vm_offset_t) 0;
128: thread->pc_sample.seqno = 0;
129: thread->pc_sample.sampletypes = 0; /* shut off sampling */
130:
131: return KERN_SUCCESS;
132: }
133:
134: kern_return_t
135: task_disable_pc_sampling(
136: task_t task,
137: int *samplecntp)
138: {
139: vm_offset_t buf;
140:
141: if (task == TASK_NULL) {
142: return KERN_INVALID_ARGUMENT;
143: }
144: if ((buf = task->pc_sample.buffer) != 0)
145: kfree(buf, sizeof (sampled_pcs));
146: task->pc_sample.buffer = (vm_offset_t) 0;
147: task->pc_sample.seqno = 0;
148: task->pc_sample.sampletypes = 0; /* shut off sampling */
149:
150: return KERN_SUCCESS;
151: }
152:
153: static kern_return_t
154: get_sampled_pcs(
155: sample_control_t *cp,
156: sampled_pc_seqno_t *seqnop,
157: sampled_pc_array_t sampled_pcs_out,
158: int *sampled_pcs_cntp)
159: {
160: int nsamples;
161: sampled_pc_seqno_t seqidx1, seqidx2;
162:
163: nsamples = cp->seqno - *seqnop;
164: seqidx1 = *seqnop % MAX_PC_SAMPLES; /* index of *seqnop */
165: seqidx2 = cp->seqno % MAX_PC_SAMPLES; /* index of cp->seqno */
166:
167: if (nsamples > MAX_PC_SAMPLES) {
168: nsamples = MAX_PC_SAMPLES;
169: seqidx1 = (seqidx2 + 1) % MAX_PC_SAMPLES;
170: }
171:
172: if (nsamples > 0) {
173: /*
174: * Carefully copy sampled_pcs into sampled_pcs_msgbuf IN ORDER.
175: */
176: if (seqidx1 < seqidx2) {
177: /*
178: * Simple case: no wraparound.
179: * Copy from seqidx1 to seqidx2.
180: */
181: bcopy((sampled_pc_array_t)cp->buffer + seqidx1 + 1,
182: sampled_pcs_out,
183: nsamples * sizeof(sampled_pc_t));
184: } else {
185: /* seqidx1 > seqidx2 -- Handle wraparound. */
186:
187: bcopy((sampled_pc_array_t)cp->buffer + seqidx1 + 1,
188: sampled_pcs_out,
189: (MAX_PC_SAMPLES - seqidx1 - 1) * sizeof(sampled_pc_t));
190:
191: bcopy((sampled_pc_array_t)cp->buffer,
192: sampled_pcs_out + (MAX_PC_SAMPLES - seqidx1 - 1),
193: (seqidx2 + 1) * sizeof(sampled_pc_t));
194: }
195: } else {
196: /* could either be zero because of overflow, or because
197: * we are being lied to. In either case, return nothing.
198: * If overflow, only once in a blue moon. If being lied to,
199: * then we have no obligation to return anything useful anyway.
200: */
201: ;
202: }
203:
204: *sampled_pcs_cntp = nsamples;
205: *seqnop = cp->seqno;
206: return KERN_SUCCESS;
207: }
208:
209: kern_return_t
210: thread_get_sampled_pcs(
211: thread_t thread,
212: sampled_pc_seqno_t *seqnop,
213: sampled_pc_array_t sampled_pcs_out,
214: int *sampled_pcs_cntp)
215: {
216: if (thread == THREAD_NULL)
217: return KERN_INVALID_ARGUMENT;
218:
219: if (thread->pc_sample.buffer == 0)
220: return KERN_FAILURE;
221:
222: return get_sampled_pcs(&thread->pc_sample, seqnop, sampled_pcs_out,
223: sampled_pcs_cntp);
224: }
225:
226: kern_return_t
227: task_get_sampled_pcs(
228: task_t task,
229: sampled_pc_seqno_t *seqnop,
230: sampled_pc_array_t sampled_pcs_out,
231: int *sampled_pcs_cntp)
232: {
233: if (task == TASK_NULL)
234: return KERN_INVALID_ARGUMENT;
235:
236: if (task->pc_sample.buffer == 0)
237: return KERN_FAILURE;
238:
239: return get_sampled_pcs(&task->pc_sample, seqnop, sampled_pcs_out,
240: sampled_pcs_cntp);
241: }
242:
243: #else /* MACH_PCSAMPLE */
244:
245: kern_return_t
246: thread_enable_pc_sampling(
247: thread_t thread,
248: int *tickp,
249: sampled_pc_flavor_t flavors)
250: {
251: return KERN_FAILURE; /* not implemented */
252: }
253:
254: kern_return_t
255: task_enable_pc_sampling(
256: task_t task,
257: int *tickp,
258: sampled_pc_flavor_t flavors)
259: {
260: return KERN_FAILURE; /* not implemented */
261: }
262:
263: kern_return_t
264: thread_disable_pc_sampling(
265: thread_t thread,
266: int *samplecntp)
267: {
268: return KERN_FAILURE; /* not implemented */
269: }
270:
271: kern_return_t
272: task_disable_pc_sampling(
273: task_t task,
274: int *samplecntp)
275: {
276: return KERN_FAILURE; /* not implemented */
277: }
278:
279: kern_return_t
280: thread_get_sampled_pcs(
281: thread_t thread,
282: sampled_pc_seqno_t *seqnop,
283: sampled_pc_array_t sampled_pcs_out,
284: int *sampled_pcs_cntp)
285: {
286: return KERN_FAILURE; /* not implemented */
287: }
288:
289: kern_return_t
290: task_get_sampled_pcs(
291: task_t task,
292: sampled_pc_seqno_t *seqnop,
293: sampled_pc_array_t sampled_pcs_out,
294: int *sampled_pcs_cntp)
295: {
296: return KERN_FAILURE; /* not implemented */
297: }
298:
299: #endif /* MACH_PCSAMPLE */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.