6324 Add an `ndp' tool for manipulating the neighbors table
[illumos-gate.git] / usr / src / uts / common / tnf / trace_funcs.c
blob96b3e8eed559ffc0b54a41be777940d40fd1381b
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 (c) 1994, by Sun Microsytems, Inc.
26 #pragma ident "%Z%%M% %I% %E% SMI"
29 * Includes
31 #include <sys/param.h>
32 #include <sys/time.h>
33 #include <sys/debug.h>
34 #include <sys/cmn_err.h>
35 #include <sys/tnf.h>
37 #include "tnf_buf.h"
38 #include "tnf_types.h"
39 #include "tnf_trace.h"
42 * Defines
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) \
66 (((x) >> 32) == 0)
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)))
76 * Typedefs
79 typedef struct {
80 tnf_probe_event_t probe_event;
81 tnf_time_delta_t time_delta;
82 } probe_event_prototype_t;
85 * Declarations
89 * tnf_trace_alloc
90 * the probe allocation function
93 void *
94 tnf_trace_alloc(tnf_ops_t *ops, tnf_probe_control_t *probe_p,
95 tnf_probe_setup_t *set_p)
97 TNFW_B_WCB *wcb;
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;
102 tnf_uint32_t shift;
103 probe_event_prototype_t *buffer;
104 hrtime_t curr_time, time_diff;
105 tnf_schedule_t *sched;
106 tnf_ref32_t *fwd_p;
107 size_t size, asize;
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 */
116 return (NULL);
117 if (!tnf_tracing_active)
118 goto null_ret;
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)
126 goto null_ret;
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;
139 else
140 /* rare case -- get an extra fwd ptr */
141 asize += sizeof (tnf_ref32_t);
144 * Allocate memory
146 wcb = &ops->wcb;
147 /* LINTED assignment of 64-bit integer to 16-bit integer */
148 TNFW_B_ALLOC(wcb, asize, buffer, probe_event_prototype_t *);
149 if (buffer == NULL)
150 goto null_ret;
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;
167 fwd_p++;
171 * Get timestamp
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 */
186 goto new_schedule;
189 * Note: Don't bother about space bit here, because we'll
190 * only use bits 15:2 anyway
192 #if defined(_LP64)
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);
196 #else
197 sched_offset = ((sched->record_gen - block->generation) << shift) +
198 (sched_record_p - (caddr_t)buffer);
199 #endif
200 if (!TAGARG_CHECK(sched_offset))
201 /* Record too far away to reference */
202 goto new_schedule;
204 time_diff = curr_time - sched->time_base;
205 if (!TIME_CHECK(time_diff))
206 /* Time delta can't fit in 32 bits */
207 goto new_schedule;
209 if (sched->cpuid != CPU->cpu_id)
210 /* CPU information is invalid */
211 goto new_schedule;
214 * Can reuse existing schedule record
215 * Since we did not allocate any more space, can giveback
217 #if defined(_LP64)
218 /* LINTED warning: assignment of 64-bit integer to 16-bit integer */
219 TNFW_B_GIVEBACK(wcb, fwd_p);
220 #else
221 TNFW_B_GIVEBACK(wcb, fwd_p);
222 #endif
224 good_ret:
226 * Store return params and two common event members, return buffer
228 set_p->tpd_p = ops;
229 set_p->buffer_p = buffer;
230 set_p->probe_p = probe_p;
231 buffer->probe_event = ENCODED_TAG(tag_disp, sched_offset);
232 #if defined(_LP64)
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);
236 #else
237 buffer->time_delta = tnf_time_delta(ops, (unsigned long)time_diff,
238 &buffer->probe_time_delta);
239 #endif
240 return (buffer);
242 new_schedule:
244 * Write a new schedule record for this thread
246 sched->cpuid = CPU->cpu_id;
247 sched->time_base = curr_time;
248 time_diff = 0;
249 if ((sched_record_p = tnf_kernel_schedule(ops, sched)) != NULL) {
250 /* use one of the extra alloced words for the forwarding ptr */
251 #if defined(_LP64)
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) +
255 /* LINTED */
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);
259 #else
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);
264 #endif
265 } else {
266 /* Allocation failed (tracing may have been stopped) */
267 sched_offset = 0;
268 *fwd_p = TNF_NULL;
270 goto good_ret;
272 null_ret:
274 * Clear busy flag and return null
276 LOCK_INIT_CLEAR(&ops->busy); /* XXX save a call */
277 return (NULL);
281 * tnf_trace_commit
283 void
284 tnf_trace_commit(tnf_probe_setup_t *set_p)
286 tnf_ops_t *ops;
287 TNFW_B_WCB *wcb;
288 TNFW_B_POS *pos;
290 ops = set_p->tpd_p;
291 wcb = &ops->wcb;
293 /* commit reusable bytes */
294 pos = &wcb->tnfw_w_pos;
295 TNFW_B_COMMIT(pos);
297 /* commit tag bytes */
298 pos = &wcb->tnfw_w_tag_pos;
299 TNFW_B_COMMIT(pos);
301 /* clear busy flag */
302 LOCK_INIT_CLEAR(&ops->busy); /* XXX save a call */
306 * tnf_trace_rollback
308 void
309 tnf_trace_rollback(tnf_probe_setup_t *set_p)
311 tnf_ops_t *ops;
312 TNFW_B_WCB *wcb;
313 TNFW_B_POS *pos;
315 ops = set_p->tpd_p;
316 wcb = &ops->wcb;
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;
324 TNFW_B_COMMIT(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 */
334 * tnf_allocate
335 * exported interface for allocating trace memory
338 void *
339 tnf_allocate(tnf_ops_t *ops, size_t size)
341 return (tnfw_b_alloc(&ops->wcb, size, ops->mode));