add debug printout
[babeltrace.git] / plugins / ctf / fs / data-stream.c
CommitLineData
e98a2d6e
PP
1/*
2 * Copyright 2016 - Philippe Proulx <pproulx@efficios.com>
3 * Copyright 2010-2011 - EfficiOS Inc. and Linux Foundation
4 *
5 * Some functions are based on older functions written by Mathieu Desnoyers.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 * SOFTWARE.
24 */
25
26#include <stdio.h>
27#include <stdint.h>
28#include <stdlib.h>
29#include <stdbool.h>
30#include <glib.h>
31#include <inttypes.h>
32#include <sys/mman.h>
33#include <babeltrace/ctf-ir/stream.h>
34
35#define PRINT_ERR_STREAM ctf_fs->error_fp
36#define PRINT_PREFIX "ctf-fs-data-stream"
37#include "print.h"
38
56a1cced
JG
39#include "file.h"
40#include "metadata.h"
41#include "../common/notif-iter/notif-iter.h"
e98a2d6e
PP
42
43static void ctf_fs_stream_destroy(struct ctf_fs_stream *stream)
44{
45 if (stream->file) {
46 ctf_fs_file_destroy(stream->file);
47 }
48
49 if (stream->stream) {
50 BT_PUT(stream->stream);
51 }
52
53 if (stream->notif_iter) {
54 bt_ctf_notif_iter_destroy(stream->notif_iter);
55 }
56
57 g_free(stream);
58}
59
60static size_t remaining_mmap_bytes(struct ctf_fs_stream *stream)
61{
62 return stream->mmap_offset + stream->mmap_len -
63 stream->request_offset;
64}
65
66static int stream_munmap(struct ctf_fs_stream *stream)
67{
56a1cced 68 struct ctf_fs_component *ctf_fs = stream->file->ctf_fs;
e98a2d6e
PP
69
70 if (munmap(stream->mmap_addr, stream->mmap_len)) {
71 PERR("Cannot memory-unmap address %p (size %zu) of file \"%s\" (%p): %s\n",
72 stream->mmap_addr, stream->mmap_len,
73 stream->file->path->str, stream->file->fp,
74 strerror(errno));
75 return -1;
76 }
77
78 return 0;
79}
80
81static int mmap_next(struct ctf_fs_stream *stream)
82{
56a1cced 83 struct ctf_fs_component *ctf_fs = stream->file->ctf_fs;
e98a2d6e
PP
84 int ret = 0;
85
86 /* Unmap old region */
87 if (stream->mmap_addr) {
88 if (stream_munmap(stream)) {
89 goto error;
90 }
91
92 stream->mmap_offset += stream->mmap_len;
93 stream->request_offset = stream->mmap_offset;
94 }
95
96 /* Map new region */
97 stream->mmap_addr = mmap((void *) 0, stream->mmap_len,
98 PROT_READ, MAP_PRIVATE, fileno(stream->file->fp),
99 stream->mmap_offset);
100 if (stream->mmap_addr == MAP_FAILED) {
101 PERR("Cannot memory-map address (size %zu) of file \"%s\" (%p) at offset %zu: %s\n",
102 stream->mmap_len, stream->file->path->str,
103 stream->file->fp, stream->mmap_offset,
104 strerror(errno));
105 goto error;
106 }
107
108 goto end;
109
110error:
111 stream_munmap(stream);
112 ret = -1;
113
114end:
115 return ret;
116}
117
118static enum bt_ctf_notif_iter_medium_status medop_request_bytes(
119 size_t request_sz, uint8_t **buffer_addr,
120 size_t *buffer_sz, void *data)
121{
122 enum bt_ctf_notif_iter_medium_status status =
123 BT_CTF_NOTIF_ITER_MEDIUM_STATUS_OK;
124 struct ctf_fs_stream *stream = data;
56a1cced 125 struct ctf_fs_component *ctf_fs = stream->file->ctf_fs;
e98a2d6e
PP
126
127 if (request_sz == 0) {
128 goto end;
129 }
130
131 /* Check if we need an initial memory map */
132 if (!stream->mmap_addr) {
133 if (mmap_next(stream)) {
134 PERR("Cannot memory-map initial region of file \"%s\" (%p)\n",
135 stream->file->path->str, stream->file->fp);
136 goto error;
137 }
138 }
139
140 /* Check if we have at least one memory-mapped byte left */
141 if (remaining_mmap_bytes(stream) == 0) {
142 /* Are we at the end of the file? */
143 if (stream->request_offset == stream->file->size) {
144 PDBG("Reached end of file \"%s\" (%p)\n",
145 stream->file->path->str, stream->file->fp);
146 status = BT_CTF_NOTIF_ITER_MEDIUM_STATUS_EOF;
147 goto end;
148 }
149
150 if (mmap_next(stream)) {
151 PERR("Cannot memory-map next region of file \"%s\" (%p)\n",
152 stream->file->path->str, stream->file->fp);
153 goto error;
154 }
155 }
156
157 *buffer_sz = MIN(remaining_mmap_bytes(stream), request_sz);
158 *buffer_addr = ((uint8_t *) stream->mmap_addr) +
159 stream->request_offset - stream->mmap_offset;
160 stream->request_offset += *buffer_sz;
161 goto end;
162
163error:
164 status = BT_CTF_NOTIF_ITER_MEDIUM_STATUS_ERROR;
165
166end:
167 return status;
168}
169
170static struct bt_ctf_stream *medop_get_stream(
171 struct bt_ctf_stream_class *stream_class, void *data)
172{
173 struct ctf_fs_stream *fs_stream = data;
56a1cced 174 struct ctf_fs_component *ctf_fs = fs_stream->file->ctf_fs;
e98a2d6e
PP
175
176 if (!fs_stream->stream) {
177 int64_t id = bt_ctf_stream_class_get_id(stream_class);
178
179 PDBG("Creating stream out of stream class %" PRId64 "\n", id);
180 fs_stream->stream = bt_ctf_stream_create(stream_class,
181 fs_stream->file->path->str);
182 if (!fs_stream->stream) {
183 PERR("Cannot create stream (stream class %" PRId64 ")\n",
184 id);
185 }
186 }
187
188 return fs_stream->stream;
189}
190
191static struct bt_ctf_notif_iter_medium_ops medops = {
192 .request_bytes = medop_request_bytes,
193 .get_stream = medop_get_stream,
194};
195
56a1cced
JG
196static struct ctf_fs_stream *ctf_fs_stream_create(
197 struct ctf_fs_component *ctf_fs, struct ctf_fs_file *file)
e98a2d6e
PP
198{
199 struct ctf_fs_stream *stream = g_new0(struct ctf_fs_stream, 1);
200
201 if (!stream) {
202 goto error;
203 }
204
205 stream->file = file;
206 stream->notif_iter = bt_ctf_notif_iter_create(ctf_fs->metadata.trace,
207 12, medops, stream, ctf_fs->error_fp);
208 if (!stream->notif_iter) {
209 goto error;
210 }
211 stream->mmap_len = ctf_fs->page_size;
212
213 goto end;
214
215error:
216 /* Do not touch borrowed file */
217 stream->file = NULL;
218 ctf_fs_stream_destroy(stream);
219 stream = NULL;
220
221end:
222 return stream;
223}
224
56a1cced 225int ctf_fs_data_stream_open_streams(struct ctf_fs_component *ctf_fs)
e98a2d6e
PP
226{
227 int ret = 0;
228 GError *error = NULL;
229 GDir *dir = g_dir_open(ctf_fs->trace_path->str, 0, &error);
230 const char *name;
231
232 if (!dir) {
233 PERR("Cannot open directory \"%s\": %s (code %d)\n",
234 ctf_fs->trace_path->str, error->message,
235 error->code);
236 goto error;
237 }
238
239 while ((name = g_dir_read_name(dir))) {
240 struct ctf_fs_file *file = NULL;
241 struct ctf_fs_stream *stream = NULL;
242
243 if (strcmp(name, CTF_FS_METADATA_FILENAME) == 0) {
244 /* Ignore the metadata stream */
245 PDBG("Ignoring metadata file \"%s\"\n",
246 name);
247 continue;
248 }
249
250 if (name[0] == '.') {
251 PDBG("Ignoring hidden file \"%s\"\n",
252 name);
253 continue;
254 }
255
256 /* Create the file */
257 file = ctf_fs_file_create(ctf_fs);
258 if (!file) {
259 PERR("Cannot create stream file object\n");
260 goto error;
261 }
262
263 /* Create full path string */
264 g_string_append(file->path, ctf_fs->trace_path->str);
265 g_string_append(file->path, "/");
266 g_string_append(file->path, name);
267
268 if (!g_file_test(file->path->str, G_FILE_TEST_IS_REGULAR)) {
269 PDBG("Ignoring non-regular file \"%s\"\n", name);
270 ctf_fs_file_destroy(file);
271 continue;
272 }
273
274 /* Open the file */
275 if (ctf_fs_file_open(ctf_fs, file, "rb")) {
276 ctf_fs_file_destroy(file);
277 goto error;
278 }
279
280 /* Create a private stream */
281 stream = ctf_fs_stream_create(ctf_fs, file);
282 if (!stream) {
283 ctf_fs_file_destroy(file);
284 goto error;
285 }
286
287 /* Append file to the array of files */
288 g_ptr_array_add(ctf_fs->data_stream.streams, stream);
289 }
290
291 goto end;
292
293error:
294 ret = -1;
295
296end:
297 if (dir) {
298 g_dir_close(dir);
299 dir = NULL;
300 }
301
302 if (error) {
303 g_error_free(error);
304 }
305
306 return ret;
307}
308
56a1cced 309int ctf_fs_data_stream_init(struct ctf_fs_component *ctf_fs,
e98a2d6e
PP
310 struct ctf_fs_data_stream *data_stream)
311{
312 int ret = 0;
313
314 data_stream->streams = g_ptr_array_new_with_free_func(
315 (GDestroyNotify) ctf_fs_stream_destroy);
316 if (!data_stream->streams) {
317 PERR("Cannot allocate array of streams\n");
318 goto error;
319 }
320
321 goto end;
322
323error:
324 ret = -1;
325
326end:
327 return ret;
328}
329
413bc2c4 330void ctf_fs_data_stream_fini(struct ctf_fs_data_stream *data_stream)
e98a2d6e
PP
331{
332 g_ptr_array_free(data_stream->streams, TRUE);
333}
334
335int ctf_fs_data_stream_get_next_notification(
56a1cced 336 struct ctf_fs_component *ctf_fs,
e98a2d6e
PP
337 struct bt_ctf_notif_iter_notif **notification)
338{
339 int ret = 0;
340 struct ctf_fs_stream *stream = g_ptr_array_index(
341 ctf_fs->data_stream.streams, 0);
342 enum bt_ctf_notif_iter_status status;
343
344 status = bt_ctf_notif_iter_get_next_notification(
345 stream->notif_iter, notification);
346 if (status != BT_CTF_NOTIF_ITER_STATUS_OK &&
347 status != BT_CTF_NOTIF_ITER_STATUS_EOF) {
348 goto error;
349 }
350 if (status == BT_CTF_NOTIF_ITER_STATUS_EOF) {
351 *notification = NULL;
352 }
353
354 goto end;
355
356error:
357 ret = -1;
358
359end:
360 return ret;
361}
This page took 0.03608 seconds and 4 git commands to generate.