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
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]
23 * Copyright (c) 1994, by Sun Microsytems, Inc.
26 #pragma ident "%Z%%M% %I% %E% SMI"
43 #include "tnf_trace.h"
49 #define ASSERT(expr) assert(expr)
51 #define ENCODED_TAG(tag, tagarg) \
52 (((tag) | ((tagarg) & 0xfffc)) | TNF_REF32_T_PAIR)
55 * CAUTION: halfword_accessible assumes that the pointer is to a reclaimable
56 * block - i.e. negative offsets have a 0 in high bit
58 #define HALFWORD_ACCESSIBLE(x) \
59 ((((x) & 0xffff8000) == 0) || (((x) & 0xffff8000) == 0x7fff8000))
62 * Check that x can be encoded in tagarg slot
63 * Same as above, but operates on ints (no space bit)
65 #define TAGARG_CHECK(x) \
66 (((x) < 32767) && ((x) > -32768))
69 * Check that hi 32 bits of hrtime are zero
71 #define TIME_CHECK(x) \
75 * CAUTION: Use the following macro only when doing a self relative pointer
76 * to a target in the same block
78 #define PTR_DIFF(item, ref) \
79 ((tnf_ref32_t)((tnf_record_p)(item) - (tnf_record_p)(ref)))
86 tnf_probe_event_t probe_event
;
87 tnf_time_delta_t time_delta
;
88 } probe_event_prototype_t
;
92 * the probe allocation function
95 #define IS_NEWBLOCK(blockArray, dataBuffer) \
96 (((caddr_t)&blockArray[1]) == (caddr_t)dataBuffer)
99 tnf_trace_alloc(tnf_ops_t
*ops
, tnf_probe_control_t
*probe_p
,
100 tnf_probe_setup_t
*set_p
)
103 volatile char *file_start
;
104 uintptr_t probe_index
;
105 tnf_record_p sched_record_p
;
106 tnf_reference_t sched_offset
, tag_disp
;
107 tnf_block_header_t
*block
;
109 probe_event_prototype_t
*buffer
;
110 hrtime_t curr_time
, time_diff
;
111 tnf_schedule_t
*sched
;
114 #if defined(DEBUG) || defined(VERYVERBOSE)
120 /* check if already in a probe */
127 sprintf(tmp_buf
, "tnf_trace_alloc: begin\n");
128 (void) write(2, tmp_buf
, strlen(tmp_buf
));
132 * CAUTION: Ordering of function calls in this file is critical because
133 * we call TNFW_B_GIVEBACK. Between the time we allocate space for the
134 * event and call TNFW_B_GIVEBACK there can be no other allocations!!
138 * Write probe tag if needed
140 probe_index
= probe_p
->index
;
142 sprintf(tmp_buf
, "tnf_trace_alloc: (1) probe_index=%p\n", probe_index
);
143 (void) write(2, tmp_buf
, strlen(tmp_buf
));
145 if (probe_index
== 0) {
146 if ((probe_index
= tnf_probe_tag(ops
, probe_p
)) == 0) {
148 sprintf(tmp_buf
, "tnf_trace_alloc: (2) probe_index=%p\n",
150 (void) write(2, tmp_buf
, strlen(tmp_buf
));
151 sprintf(tmp_buf
, "tnf_trace_alloc: goto null_ret\n");
152 (void) write(2, tmp_buf
, strlen(tmp_buf
));
159 sprintf(tmp_buf
, "tnf_trace_alloc: (3) probe_index=%p\n",
161 (void) write(2, tmp_buf
, strlen(tmp_buf
));
166 * Determine how much memory is required
168 size
= probe_p
->tnf_event_size
;
169 asize
= size
+ sizeof (tnf_ref32_t
); /* one fwd ptr */
171 if (PROBE_IS_FILE_PTR(probe_index
)) {
172 /* common case - probe_index is a file ptr */
173 tag_disp
= probe_index
& PROBE_INDEX_LOW_MASK
;
175 /* rare case -- get an extra fwd ptr */
176 asize
+= sizeof (tnf_ref32_t
);
185 sprintf(tmp_buf
, "tnf_trace_alloc, wcb=%p\n", wcb
);
186 (void) write(2, tmp_buf
, strlen(tmp_buf
));
189 buffer
= ops
->alloc(wcb
, asize
, ops
->mode
);
192 sprintf(tmp_buf
, "tnf_trace_alloc, buffer=%p\n", buffer
);
193 (void) write(2, tmp_buf
, strlen(tmp_buf
));
198 /* LINTED pointer cast may result in improper alignment */
199 fwd_p
= (tnf_ref32_t
*) ((char *)(buffer
) + size
);
202 sprintf(tmp_buf
, "tnf_trace_alloc, fwd_pr=%p\n", fwd_p
);
203 (void) write(2, tmp_buf
, strlen(tmp_buf
));
206 /* set file_start after calling alloc because it allocs the file */
207 file_start
= _tnfw_b_control
->tnf_buffer
;
209 /* Check if the probe tag needs more work */
210 if (!PROBE_IS_FILE_PTR(probe_index
)) {
211 /* LINTED use up first fwd ptr */
212 *fwd_p
= TNF_REF32_MAKE_PERMANENT(
213 /* LINTED ptr subtraction */
214 (tnf_record_p
)probe_index
- (tnf_record_p
) file_start
);
215 /* LINTED ptr subtraction */
216 tag_disp
= PTR_DIFF(fwd_p
, buffer
);
217 ASSERT(TAGARG_CHECK(tag_disp
));
218 tag_disp
|= TNF_TAG16_T_REL
;
219 tag_disp
= tag_disp
<< TNF_REF32_TAG16_SHIFT
;
226 curr_time
= gethrtime();
229 * initialize and write schedule record if needed
230 * watch out for sched->record_p - it has to be checked after alloc is
231 * called for the event, because it could be side effected by alloc
232 * if a fork happened. Pre-requisite to our algorithm - if a fork
233 * happens all other threads have to be quiescent i.e. not in a probe.
235 sched
= &(ops
->schedule
);
238 sprintf(tmp_buf
, "tnf_trace_alloc, sched=%p\n", sched
);
239 (void) write(2, tmp_buf
, strlen(tmp_buf
));
242 /* LINTED pointer cast */
243 shift
= ((tnf_buf_file_header_t
*)file_start
)->com
.file_log_size
;
244 block
= (tnf_block_header_t
*)((ulong_t
)buffer
& TNF_BLOCK_MASK
);
246 if ((sched_record_p
= sched
->record_p
) == NULL
||
247 IS_NEWBLOCK(block
, buffer
)) {
248 /* No record written yet */
253 * Note: Don't bother about space bit here, because we'll
254 * only use bits 15:2 anyway
256 sched_offset
= ((sched
->record_gen
- block
->generation
) << shift
) +
257 /* LINTED - ptr subtraction */
258 (uint_t
) (sched_record_p
- (caddr_t
)buffer
);
260 if (!TAGARG_CHECK(sched_offset
))
261 /* Record too far away to reference */
264 time_diff
= curr_time
- sched
->time_base
;
265 if (!TIME_CHECK(time_diff
))
266 /* Time delta can't fit in 32 bits */
270 * Can reuse existing schedule record
271 * Since we did not allocate any more space, can giveback
273 /* LINTED - GIVEBACK returns a pointer subtraction */
274 TNFW_B_GIVEBACK(wcb
, fwd_p
);
278 * Store return params and two common event members, return buffer
281 set_p
->buffer_p
= buffer
;
282 set_p
->probe_p
= probe_p
;
283 buffer
->probe_event
= ENCODED_TAG(tag_disp
, sched_offset
);
284 /* LINTED - TIME_CHECK already passed, see above */
285 buffer
->time_delta
= tnf_time_delta(ops
, (unsigned long)time_diff
,
286 &buffer
->probe_time_delta
);
291 * Write a new schedule record for this thread
294 sprintf(tmp_buf
, " tnf_trace_alloc: initializing "
295 "new schedule record\n");
296 (void) write(2, tmp_buf
, strlen(tmp_buf
));
298 _tnf_sched_init(sched
, curr_time
);
300 if ((sched_record_p
= tnf_schedule_write(ops
, sched
)) != NULL
) {
301 /* use one of the extra alloced words for the forwarding ptr */
302 /* LINTED - ptr subtraction */
303 *fwd_p
= TNF_REF32_MAKE_RECLAIMABLE(
304 ((sched
->record_gen
- block
->generation
) << shift
) +
305 (sched_record_p
- (tnf_record_p
)fwd_p
));
306 /* LINTED - ptr subtraction */
307 sched_offset
= PTR_DIFF(fwd_p
, buffer
);
308 ASSERT(TAGARG_CHECK(sched_offset
));
310 /* Allocation failed (tracing may have been stopped) */
318 * reset re-entrancy protector, because tnf_trace_end() will
322 sprintf(tmp_buf
, "tnf_trace_alloc: null return\n");
323 (void) write(2, tmp_buf
, strlen(tmp_buf
));
331 * the last (usually only) function in the list of probe functions
334 tnf_trace_end(tnf_probe_setup_t
*set_p
)
339 sprintf(tmp_buf
, "tnf_trace_end: \n");
340 (void) write(2, tmp_buf
, strlen(tmp_buf
));
343 (set_p
->probe_p
->commit_func
)(set_p
);
344 set_p
->tpd_p
->busy
= 0;
349 * a probe commit function that really commits trace data
352 tnf_trace_commit(tnf_probe_setup_t
*set_p
)
357 sprintf(tmp_buf
, "tnf_trace_commit: \n\n");
358 (void) write(2, tmp_buf
, strlen(tmp_buf
));
360 (void) set_p
->tpd_p
->commit(&(set_p
->tpd_p
->wcb
));
368 * a probe commit function that unrolls trace data
371 tnf_trace_rollback(tnf_probe_setup_t
*set_p
)
376 sprintf(tmp_buf
, "tnf_trace_rollback: \n\n");
377 (void) write(2, tmp_buf
, strlen(tmp_buf
));
379 (void) set_p
->tpd_p
->rollback(&(set_p
->tpd_p
->wcb
));
387 * exported interface for allocating trace memory
391 tnf_allocate(tnf_ops_t
*ops
, size_t size
)
397 sprintf(tmp_buf
, "tnf_allocate\n");
398 (void) write(2, tmp_buf
, strlen(tmp_buf
));
401 retval
= ops
->alloc(&(ops
->wcb
), size
, ops
->mode
);
404 sprintf(tmp_buf
, "tnf_allocate, retval=%p\n", retval
);
405 (void) write(2, tmp_buf
, strlen(tmp_buf
));