Add ctf-reader prototype
[babeltrace.git] / ctf-reader-proto / 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
39#include "ctf-fs.h"
40#include "ctf-fs-file.h"
41#include "ctf-fs-metadata.h"
42#include "ctf-notif-iter/ctf-notif-iter.h"
43
44static void ctf_fs_stream_destroy(struct ctf_fs_stream *stream)
45{
46 if (stream->file) {
47 ctf_fs_file_destroy(stream->file);
48 }
49
50 if (stream->stream) {
51 BT_PUT(stream->stream);
52 }
53
54 if (stream->notif_iter) {
55 bt_ctf_notif_iter_destroy(stream->notif_iter);
56 }
57
58 g_free(stream);
59}
60
61static size_t remaining_mmap_bytes(struct ctf_fs_stream *stream)
62{
63 return stream->mmap_offset + stream->mmap_len -
64 stream->request_offset;
65}
66
67static int stream_munmap(struct ctf_fs_stream *stream)
68{
69 struct ctf_fs *ctf_fs = stream->file->ctf_fs;
70
71 if (munmap(stream->mmap_addr, stream->mmap_len)) {
72 PERR("Cannot memory-unmap address %p (size %zu) of file \"%s\" (%p): %s\n",
73 stream->mmap_addr, stream->mmap_len,
74 stream->file->path->str, stream->file->fp,
75 strerror(errno));
76 return -1;
77 }
78
79 return 0;
80}
81
82static int mmap_next(struct ctf_fs_stream *stream)
83{
84 struct ctf_fs *ctf_fs = stream->file->ctf_fs;
85 int ret = 0;
86
87 /* Unmap old region */
88 if (stream->mmap_addr) {
89 if (stream_munmap(stream)) {
90 goto error;
91 }
92
93 stream->mmap_offset += stream->mmap_len;
94 stream->request_offset = stream->mmap_offset;
95 }
96
97 /* Map new region */
98 stream->mmap_addr = mmap((void *) 0, stream->mmap_len,
99 PROT_READ, MAP_PRIVATE, fileno(stream->file->fp),
100 stream->mmap_offset);
101 if (stream->mmap_addr == MAP_FAILED) {
102 PERR("Cannot memory-map address (size %zu) of file \"%s\" (%p) at offset %zu: %s\n",
103 stream->mmap_len, stream->file->path->str,
104 stream->file->fp, stream->mmap_offset,
105 strerror(errno));
106 goto error;
107 }
108
109 goto end;
110
111error:
112 stream_munmap(stream);
113 ret = -1;
114
115end:
116 return ret;
117}
118
119static enum bt_ctf_notif_iter_medium_status medop_request_bytes(
120 size_t request_sz, uint8_t **buffer_addr,
121 size_t *buffer_sz, void *data)
122{
123 enum bt_ctf_notif_iter_medium_status status =
124 BT_CTF_NOTIF_ITER_MEDIUM_STATUS_OK;
125 struct ctf_fs_stream *stream = data;
126 struct ctf_fs *ctf_fs = stream->file->ctf_fs;
127
128 if (request_sz == 0) {
129 goto end;
130 }
131
132 /* Check if we need an initial memory map */
133 if (!stream->mmap_addr) {
134 if (mmap_next(stream)) {
135 PERR("Cannot memory-map initial region of file \"%s\" (%p)\n",
136 stream->file->path->str, stream->file->fp);
137 goto error;
138 }
139 }
140
141 /* Check if we have at least one memory-mapped byte left */
142 if (remaining_mmap_bytes(stream) == 0) {
143 /* Are we at the end of the file? */
144 if (stream->request_offset == stream->file->size) {
145 PDBG("Reached end of file \"%s\" (%p)\n",
146 stream->file->path->str, stream->file->fp);
147 status = BT_CTF_NOTIF_ITER_MEDIUM_STATUS_EOF;
148 goto end;
149 }
150
151 if (mmap_next(stream)) {
152 PERR("Cannot memory-map next region of file \"%s\" (%p)\n",
153 stream->file->path->str, stream->file->fp);
154 goto error;
155 }
156 }
157
158 *buffer_sz = MIN(remaining_mmap_bytes(stream), request_sz);
159 *buffer_addr = ((uint8_t *) stream->mmap_addr) +
160 stream->request_offset - stream->mmap_offset;
161 stream->request_offset += *buffer_sz;
162 goto end;
163
164error:
165 status = BT_CTF_NOTIF_ITER_MEDIUM_STATUS_ERROR;
166
167end:
168 return status;
169}
170
171static struct bt_ctf_stream *medop_get_stream(
172 struct bt_ctf_stream_class *stream_class, void *data)
173{
174 struct ctf_fs_stream *fs_stream = data;
175 struct ctf_fs *ctf_fs = fs_stream->file->ctf_fs;
176
177 if (!fs_stream->stream) {
178 int64_t id = bt_ctf_stream_class_get_id(stream_class);
179
180 PDBG("Creating stream out of stream class %" PRId64 "\n", id);
181 fs_stream->stream = bt_ctf_stream_create(stream_class,
182 fs_stream->file->path->str);
183 if (!fs_stream->stream) {
184 PERR("Cannot create stream (stream class %" PRId64 ")\n",
185 id);
186 }
187 }
188
189 return fs_stream->stream;
190}
191
192static struct bt_ctf_notif_iter_medium_ops medops = {
193 .request_bytes = medop_request_bytes,
194 .get_stream = medop_get_stream,
195};
196
197static struct ctf_fs_stream *ctf_fs_stream_create(struct ctf_fs *ctf_fs,
198 struct ctf_fs_file *file)
199{
200 struct ctf_fs_stream *stream = g_new0(struct ctf_fs_stream, 1);
201
202 if (!stream) {
203 goto error;
204 }
205
206 stream->file = file;
207 stream->notif_iter = bt_ctf_notif_iter_create(ctf_fs->metadata.trace,
208 12, medops, stream, ctf_fs->error_fp);
209 if (!stream->notif_iter) {
210 goto error;
211 }
212 stream->mmap_len = ctf_fs->page_size;
213
214 goto end;
215
216error:
217 /* Do not touch borrowed file */
218 stream->file = NULL;
219 ctf_fs_stream_destroy(stream);
220 stream = NULL;
221
222end:
223 return stream;
224}
225
226int ctf_fs_data_stream_open_streams(struct ctf_fs *ctf_fs)
227{
228 int ret = 0;
229 GError *error = NULL;
230 GDir *dir = g_dir_open(ctf_fs->trace_path->str, 0, &error);
231 const char *name;
232
233 if (!dir) {
234 PERR("Cannot open directory \"%s\": %s (code %d)\n",
235 ctf_fs->trace_path->str, error->message,
236 error->code);
237 goto error;
238 }
239
240 while ((name = g_dir_read_name(dir))) {
241 struct ctf_fs_file *file = NULL;
242 struct ctf_fs_stream *stream = NULL;
243
244 if (strcmp(name, CTF_FS_METADATA_FILENAME) == 0) {
245 /* Ignore the metadata stream */
246 PDBG("Ignoring metadata file \"%s\"\n",
247 name);
248 continue;
249 }
250
251 if (name[0] == '.') {
252 PDBG("Ignoring hidden file \"%s\"\n",
253 name);
254 continue;
255 }
256
257 /* Create the file */
258 file = ctf_fs_file_create(ctf_fs);
259 if (!file) {
260 PERR("Cannot create stream file object\n");
261 goto error;
262 }
263
264 /* Create full path string */
265 g_string_append(file->path, ctf_fs->trace_path->str);
266 g_string_append(file->path, "/");
267 g_string_append(file->path, name);
268
269 if (!g_file_test(file->path->str, G_FILE_TEST_IS_REGULAR)) {
270 PDBG("Ignoring non-regular file \"%s\"\n", name);
271 ctf_fs_file_destroy(file);
272 continue;
273 }
274
275 /* Open the file */
276 if (ctf_fs_file_open(ctf_fs, file, "rb")) {
277 ctf_fs_file_destroy(file);
278 goto error;
279 }
280
281 /* Create a private stream */
282 stream = ctf_fs_stream_create(ctf_fs, file);
283 if (!stream) {
284 ctf_fs_file_destroy(file);
285 goto error;
286 }
287
288 /* Append file to the array of files */
289 g_ptr_array_add(ctf_fs->data_stream.streams, stream);
290 }
291
292 goto end;
293
294error:
295 ret = -1;
296
297end:
298 if (dir) {
299 g_dir_close(dir);
300 dir = NULL;
301 }
302
303 if (error) {
304 g_error_free(error);
305 }
306
307 return ret;
308}
309
310int ctf_fs_data_stream_init(struct ctf_fs *ctf_fs,
311 struct ctf_fs_data_stream *data_stream)
312{
313 int ret = 0;
314
315 data_stream->streams = g_ptr_array_new_with_free_func(
316 (GDestroyNotify) ctf_fs_stream_destroy);
317 if (!data_stream->streams) {
318 PERR("Cannot allocate array of streams\n");
319 goto error;
320 }
321
322 goto end;
323
324error:
325 ret = -1;
326
327end:
328 return ret;
329}
330
331void ctf_fs_data_stream_deinit(struct ctf_fs_data_stream *data_stream)
332{
333 g_ptr_array_free(data_stream->streams, TRUE);
334}
335
336int ctf_fs_data_stream_get_next_notification(
337 struct ctf_fs *ctf_fs,
338 struct bt_ctf_notif_iter_notif **notification)
339{
340 int ret = 0;
341 struct ctf_fs_stream *stream = g_ptr_array_index(
342 ctf_fs->data_stream.streams, 0);
343 enum bt_ctf_notif_iter_status status;
344
345 status = bt_ctf_notif_iter_get_next_notification(
346 stream->notif_iter, notification);
347 if (status != BT_CTF_NOTIF_ITER_STATUS_OK &&
348 status != BT_CTF_NOTIF_ITER_STATUS_EOF) {
349 goto error;
350 }
351 if (status == BT_CTF_NOTIF_ITER_STATUS_EOF) {
352 *notification = NULL;
353 }
354
355 goto end;
356
357error:
358 ret = -1;
359
360end:
361 return ret;
362}
This page took 0.034814 seconds and 4 git commands to generate.