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"
31 #include <sys/param.h>
33 #include <sys/debug.h>
34 #include <sys/cmn_err.h>
38 #include "tnf_types.h"
39 #include "tnf_trace.h"
45 #define ENCODED_TAG(tag, tagarg) \
46 ((tag) | ((tagarg) & 0xfffc) | TNF_REF32_T_PAIR)
49 * CAUTION: halfword_accessible assumes that the pointer is to a reclaimable
50 * block - i.e. negative offsets have a 0 in high bit
52 #define HALFWORD_ACCESSIBLE(x) \
53 ((((x) & 0xffff8000) == 0) || (((x) & 0xffff8000) == 0x7fff8000))
56 * Check that x can be encoded in tagarg slot
57 * Same as above, but operates on ints (no space bit)
59 #define TAGARG_CHECK(x) \
60 (((x) < 32767) && ((x) > -32768))
63 * Check that hit 32 bits of hrtime are zero
65 #define TIME_CHECK(x) \
69 * CAUTION: Use the following macro only when doing a self relative pointer
70 * to a target in the same block
72 #define PTR_DIFF(item, ref) \
73 ((tnf_ref32_t)((tnf_record_p)(item) - (tnf_record_p)(ref)))
80 tnf_probe_event_t probe_event
;
81 tnf_time_delta_t time_delta
;
82 } probe_event_prototype_t
;
90 * the probe allocation function
94 tnf_trace_alloc(tnf_ops_t
*ops
, tnf_probe_control_t
*probe_p
,
95 tnf_probe_setup_t
*set_p
)
98 uintptr_t probe_index
;
99 tnf_record_p sched_record_p
;
100 tnf_reference_t sched_offset
, tag_disp
;
101 tnf_block_header_t
*block
;
103 probe_event_prototype_t
*buffer
;
104 hrtime_t curr_time
, time_diff
;
105 tnf_schedule_t
*sched
;
110 * Check the "tracing active" flag after setting the busy bit;
111 * this avoids a race in which we check the "tracing active"
112 * flag, then it gets turned off, and the buffer gets
113 * deallocated, before we've set the busy bit.
115 if (!lock_try(&ops
->busy
)) /* atomic op flushes WB */
117 if (!tnf_tracing_active
)
121 * Write probe tag if needed
123 probe_index
= probe_p
->index
;
124 if (probe_index
== 0) {
125 if ((probe_index
= tnf_probe_tag(ops
, probe_p
)) == 0)
130 * Determine how much memory is required
132 size
= probe_p
->tnf_event_size
;
133 asize
= size
+ sizeof (tnf_ref32_t
); /* one fwd ptr */
135 if (PROBE_IS_FILE_PTR(probe_index
))
136 /* common case - probe_index is a file ptr */
137 /* LINTED assignment of 64-bit integer to 32-bit integer */
138 tag_disp
= probe_index
& PROBE_INDEX_LOW_MASK
;
140 /* rare case -- get an extra fwd ptr */
141 asize
+= sizeof (tnf_ref32_t
);
147 /* LINTED assignment of 64-bit integer to 16-bit integer */
148 TNFW_B_ALLOC(wcb
, asize
, buffer
, probe_event_prototype_t
*);
152 /* LINTED pointer cast may result in improper alignment */
153 fwd_p
= (tnf_ref32_t
*)((char *)buffer
+ size
);
156 * Check if the probe tag needs more work
158 if (!PROBE_IS_FILE_PTR(probe_index
)) {
159 /* use up first fwd ptr */
160 /* LINTED assignment of 64-bit integer to 32-bit integer */
161 *fwd_p
= TNF_REF32_MAKE_PERMANENT(
162 (tnf_record_p
)probe_index
- tnf_buf
);
163 /* LINTED cast from 64-bit integer to 32-bit integer */
164 tag_disp
= PTR_DIFF(fwd_p
, buffer
);
165 tag_disp
|= TNF_TAG16_T_REL
;
166 tag_disp
= tag_disp
<< TNF_REF32_TAG16_SHIFT
;
173 curr_time
= gethrtime();
176 * Write schedule record if needed
178 sched
= &ops
->schedule
;
180 /* LINTED pointer cast */
181 shift
= ((tnf_buf_file_header_t
*)tnf_buf
)->com
.file_log_size
;
182 block
= (tnf_block_header_t
*)((uintptr_t)buffer
& TNF_BLOCK_MASK
);
184 if ((sched_record_p
= sched
->record_p
) == NULL
)
185 /* No record written yet */
189 * Note: Don't bother about space bit here, because we'll
190 * only use bits 15:2 anyway
193 /* LINTED assignment of 64-bit integer to 32-bit integer */
194 sched_offset
= ((sched
->record_gen
- block
->generation
) << shift
) +
195 (sched_record_p
- (caddr_t
)buffer
);
197 sched_offset
= ((sched
->record_gen
- block
->generation
) << shift
) +
198 (sched_record_p
- (caddr_t
)buffer
);
200 if (!TAGARG_CHECK(sched_offset
))
201 /* Record too far away to reference */
204 time_diff
= curr_time
- sched
->time_base
;
205 if (!TIME_CHECK(time_diff
))
206 /* Time delta can't fit in 32 bits */
209 if (sched
->cpuid
!= CPU
->cpu_id
)
210 /* CPU information is invalid */
214 * Can reuse existing schedule record
215 * Since we did not allocate any more space, can giveback
218 /* LINTED warning: assignment of 64-bit integer to 16-bit integer */
219 TNFW_B_GIVEBACK(wcb
, fwd_p
);
221 TNFW_B_GIVEBACK(wcb
, fwd_p
);
226 * Store return params and two common event members, return buffer
229 set_p
->buffer_p
= buffer
;
230 set_p
->probe_p
= probe_p
;
231 buffer
->probe_event
= ENCODED_TAG(tag_disp
, sched_offset
);
233 /* LINTED assignment of 64-bit integer to 32-bit integer */
234 buffer
->time_delta
= tnf_time_delta(ops
, (unsigned long)time_diff
,
235 &buffer
->probe_time_delta
);
237 buffer
->time_delta
= tnf_time_delta(ops
, (unsigned long)time_diff
,
238 &buffer
->probe_time_delta
);
244 * Write a new schedule record for this thread
246 sched
->cpuid
= CPU
->cpu_id
;
247 sched
->time_base
= curr_time
;
249 if ((sched_record_p
= tnf_kernel_schedule(ops
, sched
)) != NULL
) {
250 /* use one of the extra alloced words for the forwarding ptr */
252 /* LINTED assignment of 64-bit integer to 32-bit integer */
253 *fwd_p
= TNF_REF32_MAKE_RECLAIMABLE(
254 ((sched
->record_gen
- block
->generation
) << shift
) +
256 (sched_record_p
- (tnf_record_p
)fwd_p
));
257 /* LINTED cast from 64-bit integer to 32-bit integer */
258 sched_offset
= PTR_DIFF(fwd_p
, buffer
);
260 *fwd_p
= TNF_REF32_MAKE_RECLAIMABLE(
261 ((sched
->record_gen
- block
->generation
) << shift
) +
262 (sched_record_p
- (tnf_record_p
)fwd_p
));
263 sched_offset
= PTR_DIFF(fwd_p
, buffer
);
266 /* Allocation failed (tracing may have been stopped) */
274 * Clear busy flag and return null
276 LOCK_INIT_CLEAR(&ops
->busy
); /* XXX save a call */
284 tnf_trace_commit(tnf_probe_setup_t
*set_p
)
293 /* commit reusable bytes */
294 pos
= &wcb
->tnfw_w_pos
;
297 /* commit tag bytes */
298 pos
= &wcb
->tnfw_w_tag_pos
;
301 /* clear busy flag */
302 LOCK_INIT_CLEAR(&ops
->busy
); /* XXX save a call */
309 tnf_trace_rollback(tnf_probe_setup_t
*set_p
)
318 /* rollback data bytes */
319 pos
= &wcb
->tnfw_w_pos
;
320 TNFW_B_ROLLBACK(pos
);
322 /* commit tag bytes */
323 pos
= &wcb
->tnfw_w_tag_pos
;
326 /* zap schedule record, since it is in uncommitted store */
327 ops
->schedule
.record_p
= NULL
;
329 /* clear busy flag */
330 LOCK_INIT_CLEAR(&ops
->busy
); /* XXX save a call */
335 * exported interface for allocating trace memory
339 tnf_allocate(tnf_ops_t
*ops
, size_t size
)
341 return (tnfw_b_alloc(&ops
->wcb
, size
, ops
->mode
));