File: usdt_parser_host.c

package info (click to toggle)
dtrace 2.0.5-1
  • links: PTS
  • area: main
  • in suites: sid
  • size: 24,408 kB
  • sloc: ansic: 61,247; sh: 17,997; asm: 1,717; lex: 947; awk: 754; yacc: 695; perl: 37; sed: 17; makefile: 15
file content (180 lines) | stat: -rw-r--r-- 4,177 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
/*
 * Oracle Linux DTrace; Host-parser communication implementation.
 * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved.
 * Licensed under the Universal Permissive License v 1.0 as shown at
 * http://oss.oracle.com/licenses/upl.
 */

#include <errno.h>
#include <poll.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <libelf.h>
#include "usdt_parser.h"

/*
 * Write BUF to the parser pipe OUT.
 *
 * Returns 0 on success or a positive errno value on error.
 */
int
usdt_parser_write_one(int out, const void *buf_, size_t size)
{
	size_t i;
	char *buf = (char *) buf_;

	for (i = 0; i < size; ) {
		size_t ret;

		ret = write(out, buf + i, size - i);
		if (ret < 0) {
			switch (errno) {
			case EINTR:
				continue;
			default:
				return errno;
			}
		}

		i += ret;
	}

	return 0;
}

/*
 * Write the DOF to the parser pipe OUT.
 *
 * Returns 0 on success or a positive errno value on error.
 */
int
usdt_parser_host_write(int out, const dof_helper_t *dh, const usdt_data_t *data)
{
	int err;
	size_t cnt = 0;
	const usdt_data_t *blk;

	/* Write dof_helper_ structure. */
	if ((err = usdt_parser_write_one(out, (const char *)dh,
					 sizeof(*dh))) < 0)
		return err;

	/* Count and write nunmber of blocks that follow. */
	for (blk = data; blk != NULL; blk = blk->next)
		cnt++;

	if ((err = usdt_parser_write_one(out, (const char *)&cnt,
					 sizeof(cnt))) < 0)
		return err;

	/* Write the blocks (for each, offset, size, and data). */
	for (blk = data; blk != NULL; blk = blk->next) {
		if ((err = usdt_parser_write_one(out, (const char *)&blk->base,
						 sizeof(blk->base))) < 0)
			return err;
		if ((err = usdt_parser_write_one(out, (const char *)&blk->size,
						 sizeof(blk->size))) < 0)
			return err;
		if ((err = usdt_parser_write_one(out, (const char *)blk->buf,
						 blk->size)) < 0)
			return err;
	}

	return 0;
}

/*
 * Read a single dof_parsed_t structure from a parser pipe.  Wait at most
 * TIMEOUT seconds to do so.
 *
 * Returns NULL and sets errno on error.
 */
dof_parsed_t *
usdt_parser_host_read(int in, int timeout)
{
	size_t i, sz;
	dof_parsed_t *reply;
	struct pollfd fd;

	fd.fd = in;
	fd.events = POLLIN;

	reply = malloc(sizeof(dof_parsed_t));
	if (!reply)
		goto err;
	memset(reply, 0, sizeof(dof_parsed_t));

	/*
	 * On the first read, only read in the size.  Decide how much to read
	 * only after that, both to make sure we don't underread and to make
	 * sure we don't *overread* and concatenate part of another message
	 * onto this one.
	 *
	 * Adjust the timeout whenever we are interrupted.  If we can't figure
	 * out the time, don't bother adjusting, but still read: a read taking
	 * longer than expected is better than no read at all.
	 */
	for (i = 0, sz = offsetof(dof_parsed_t, type); i < sz;) {
		size_t ret;
		struct timespec start, end;
		int no_adjustment = 0;
		long timeout_msec = timeout * MILLISEC;

		if (clock_gettime(CLOCK_REALTIME, &start) < 0)
			no_adjustment = 1;

		while ((ret = poll(&fd, 1, timeout_msec)) <= 0 && errno == EINTR) {

			if (no_adjustment || clock_gettime(CLOCK_REALTIME, &end) < 0)
				continue; /* Abandon timeout adjustment */

			timeout_msec -= ((((unsigned long long) end.tv_sec * NANOSEC) + end.tv_nsec) -
					 (((unsigned long long) start.tv_sec * NANOSEC) + start.tv_nsec)) /
					MICROSEC;

			if (timeout_msec < 0)
				timeout_msec = 0;
		}

		if (ret < 0)
			goto err;

		while ((ret = read(in, ((char *) reply) + i, sz - i)) < 0 &&
		       errno == EINTR);

		if (ret <= 0)
			goto err;

		/*
		 * Fix up the size once it's received.  Might be large enough
		 * that we've done the initial size read...
		 */
		if (i < offsetof(dof_parsed_t, type) &&
		    i + ret >= offsetof(dof_parsed_t, type))
			sz = reply->size;

		/* Allocate more room if needed for the reply.  */
		if (sz > sizeof(dof_parsed_t)) {
			dof_parsed_t *new_reply;

			new_reply = realloc(reply, reply->size);
			if (!new_reply)
				goto err;

			memset(((char *) new_reply) + i + ret, 0, new_reply->size - (i + ret));
			reply = new_reply;
		}

		i += ret;
	}

	return reply;

err:
	free(reply);
	return NULL;
}