8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / lib / libtnfprobe / trace_funcs.c
blobb370b15c831a3d233b5c09af2789a40eaf3c2c23
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
32 #ifndef DEBUG
33 #define NDEBUG 1
34 #endif
36 #include <assert.h>
37 #include <limits.h>
38 #include <values.h>
39 #include <stdio.h>
40 #include <string.h>
41 #include <unistd.h>
43 #include "tnf_trace.h"
46 * Defines
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) \
72 (((x) >> 32) == 0)
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)))
82 * Typedefs
85 typedef struct {
86 tnf_probe_event_t probe_event;
87 tnf_time_delta_t time_delta;
88 } probe_event_prototype_t;
91 * tnf_trace_alloc
92 * the probe allocation function
95 #define IS_NEWBLOCK(blockArray, dataBuffer) \
96 (((caddr_t)&blockArray[1]) == (caddr_t)dataBuffer)
98 void *
99 tnf_trace_alloc(tnf_ops_t *ops, tnf_probe_control_t *probe_p,
100 tnf_probe_setup_t *set_p)
102 TNFW_B_WCB *wcb;
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;
108 tnf_uint32_t shift;
109 probe_event_prototype_t *buffer;
110 hrtime_t curr_time, time_diff;
111 tnf_schedule_t *sched;
112 tnf_ref32_t *fwd_p;
113 ulong_t size, asize;
114 #if defined(DEBUG) || defined(VERYVERBOSE)
115 char tmp_buf[512];
116 #endif
118 ASSERT(ops != NULL);
120 /* check if already in a probe */
121 if (ops->busy)
122 return (NULL);
123 ops->busy = 1;
126 #ifdef VERYVERBOSE
127 sprintf(tmp_buf, "tnf_trace_alloc: begin\n");
128 (void) write(2, tmp_buf, strlen(tmp_buf));
129 #endif
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;
141 #ifdef VERYVERBOSE
142 sprintf(tmp_buf, "tnf_trace_alloc: (1) probe_index=%p\n", probe_index);
143 (void) write(2, tmp_buf, strlen(tmp_buf));
144 #endif
145 if (probe_index == 0) {
146 if ((probe_index = tnf_probe_tag(ops, probe_p)) == 0) {
147 #ifdef VERYVERBOSE
148 sprintf(tmp_buf, "tnf_trace_alloc: (2) probe_index=%p\n",
149 probe_index);
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));
153 fflush(stderr);
154 sleep(2);
155 #endif
156 goto null_ret;
158 #ifdef VERYVERBOSE
159 sprintf(tmp_buf, "tnf_trace_alloc: (3) probe_index=%p\n",
160 probe_index);
161 (void) write(2, tmp_buf, strlen(tmp_buf));
162 fflush(stderr);
163 #endif
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;
174 } else {
175 /* rare case -- get an extra fwd ptr */
176 asize += sizeof (tnf_ref32_t);
180 * Allocate memory
182 wcb = &(ops->wcb);
184 #ifdef _TNF_VERBOSE
185 sprintf(tmp_buf, "tnf_trace_alloc, wcb=%p\n", wcb);
186 (void) write(2, tmp_buf, strlen(tmp_buf));
187 #endif
189 buffer = ops->alloc(wcb, asize, ops->mode);
191 #ifdef _TNF_VERBOSE
192 sprintf(tmp_buf, "tnf_trace_alloc, buffer=%p\n", buffer);
193 (void) write(2, tmp_buf, strlen(tmp_buf));
194 #endif
195 if (buffer == NULL)
196 goto null_ret;
198 /* LINTED pointer cast may result in improper alignment */
199 fwd_p = (tnf_ref32_t *) ((char *)(buffer) + size);
201 #ifdef _TNF_VERBOSE
202 sprintf(tmp_buf, "tnf_trace_alloc, fwd_pr=%p\n", fwd_p);
203 (void) write(2, tmp_buf, strlen(tmp_buf));
204 #endif
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;
220 fwd_p++;
224 * Get timestamp
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);
237 #ifdef _TNF_VERBOSE
238 sprintf(tmp_buf, "tnf_trace_alloc, sched=%p\n", sched);
239 (void) write(2, tmp_buf, strlen(tmp_buf));
240 #endif
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 */
249 goto new_schedule;
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 */
262 goto new_schedule;
264 time_diff = curr_time - sched->time_base;
265 if (!TIME_CHECK(time_diff))
266 /* Time delta can't fit in 32 bits */
267 goto new_schedule;
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);
276 good_ret:
278 * Store return params and two common event members, return buffer
280 set_p->tpd_p = ops;
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);
287 return (buffer);
289 new_schedule:
291 * Write a new schedule record for this thread
293 #ifdef VERYVERBOSE
294 sprintf(tmp_buf, " tnf_trace_alloc: initializing "
295 "new schedule record\n");
296 (void) write(2, tmp_buf, strlen(tmp_buf));
297 #endif
298 _tnf_sched_init(sched, curr_time);
299 time_diff = 0;
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));
309 } else {
310 /* Allocation failed (tracing may have been stopped) */
311 sched_offset = 0;
312 *fwd_p = TNF_NULL;
314 goto good_ret;
316 null_ret:
318 * reset re-entrancy protector, because tnf_trace_end() will
319 * not be called
321 #ifdef VERYVERBOSE
322 sprintf(tmp_buf, "tnf_trace_alloc: null return\n");
323 (void) write(2, tmp_buf, strlen(tmp_buf));
324 #endif
325 ops->busy = 0;
326 return (NULL);
330 * tnf_trace_end
331 * the last (usually only) function in the list of probe functions
333 void
334 tnf_trace_end(tnf_probe_setup_t *set_p)
336 #ifdef VERYVERBOSE
337 char tmp_buf[512];
339 sprintf(tmp_buf, "tnf_trace_end: \n");
340 (void) write(2, tmp_buf, strlen(tmp_buf));
341 #endif
343 (set_p->probe_p->commit_func)(set_p);
344 set_p->tpd_p->busy = 0;
348 * tnf_trace_commit
349 * a probe commit function that really commits trace data
351 void
352 tnf_trace_commit(tnf_probe_setup_t *set_p)
354 #ifdef VERYVERBOSE
355 char tmp_buf[512];
357 sprintf(tmp_buf, "tnf_trace_commit: \n\n");
358 (void) write(2, tmp_buf, strlen(tmp_buf));
359 #endif
360 (void) set_p->tpd_p->commit(&(set_p->tpd_p->wcb));
362 return;
367 * tnf_trace_rollback
368 * a probe commit function that unrolls trace data
370 void
371 tnf_trace_rollback(tnf_probe_setup_t *set_p)
373 #ifdef VERYVERBOSE
374 char tmp_buf[512];
376 sprintf(tmp_buf, "tnf_trace_rollback: \n\n");
377 (void) write(2, tmp_buf, strlen(tmp_buf));
378 #endif
379 (void) set_p->tpd_p->rollback(&(set_p->tpd_p->wcb));
381 return;
386 * tnf_allocate
387 * exported interface for allocating trace memory
390 void *
391 tnf_allocate(tnf_ops_t *ops, size_t size)
393 void *retval;
394 char tmp_buf[512];
396 #ifdef _TNF_VERBOSE
397 sprintf(tmp_buf, "tnf_allocate\n");
398 (void) write(2, tmp_buf, strlen(tmp_buf));
399 #endif
401 retval = ops->alloc(&(ops->wcb), size, ops->mode);
403 #ifdef _TNF_VERBOSE
404 sprintf(tmp_buf, "tnf_allocate, retval=%p\n", retval);
405 (void) write(2, tmp_buf, strlen(tmp_buf));
406 #endif
408 return (retval);