0f5b15990fd25d23b0a39f8ee6d3ce195ba67b6a
[babeltrace.git] / plugins / text / dmesg / dmesg.c
1 /*
2 * Copyright 2010-2011 EfficiOS Inc. and Linux Foundation
3 * Copyright 2017 Philippe Proulx <pproulx@efficios.com>
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 */
23
24 #define BT_LOG_TAG "PLUGIN-TEXT-DMESG-SRC"
25 #include "logging.h"
26
27 #include <stdbool.h>
28 #include <string.h>
29 #include <ctype.h>
30 #include <stdio.h>
31 #include <babeltrace/assert-internal.h>
32 #include <babeltrace/common-internal.h>
33 #include <babeltrace/babeltrace.h>
34 #include <babeltrace/values-internal.h>
35 #include <babeltrace/compat/utc-internal.h>
36 #include <babeltrace/compat/stdio-internal.h>
37 #include <glib.h>
38
39 #define NSEC_PER_USEC 1000UL
40 #define NSEC_PER_MSEC 1000000UL
41 #define NSEC_PER_SEC 1000000000ULL
42 #define USEC_PER_SEC 1000000UL
43
44 struct dmesg_component;
45
46 struct dmesg_notif_iter {
47 struct dmesg_component *dmesg_comp;
48 struct bt_self_notification_iterator *pc_notif_iter; /* Weak */
49 char *linebuf;
50 size_t linebuf_len;
51 FILE *fp;
52 struct bt_notification *tmp_event_notif;
53
54 enum {
55 STATE_EMIT_STREAM_BEGINNING,
56 STATE_EMIT_PACKET_BEGINNING,
57 STATE_EMIT_EVENT,
58 STATE_EMIT_PACKET_END,
59 STATE_EMIT_STREAM_END,
60 STATE_DONE,
61 } state;
62 };
63
64 struct dmesg_component {
65 struct {
66 GString *path;
67 bt_bool read_from_stdin;
68 bt_bool no_timestamp;
69 } params;
70
71 struct bt_trace_class *trace_class;
72 struct bt_stream_class *stream_class;
73 struct bt_event_class *event_class;
74 struct bt_trace *trace;
75 struct bt_stream *stream;
76 struct bt_packet *packet;
77 struct bt_clock_class *clock_class;
78 };
79
80 static
81 struct bt_field_class *create_event_payload_fc(void)
82 {
83 struct bt_field_class *root_fc = NULL;
84 struct bt_field_class *fc = NULL;
85 int ret;
86
87 root_fc = bt_field_class_structure_create();
88 if (!root_fc) {
89 BT_LOGE_STR("Cannot create an empty structure field class object.");
90 goto error;
91 }
92
93 fc = bt_field_class_string_create();
94 if (!fc) {
95 BT_LOGE_STR("Cannot create a string field class object.");
96 goto error;
97 }
98
99 ret = bt_field_class_structure_append_member(root_fc,
100 "str", fc);
101 if (ret) {
102 BT_LOGE("Cannot add `str` member to structure field class: "
103 "ret=%d", ret);
104 goto error;
105 }
106
107 goto end;
108
109 error:
110 BT_OBJECT_PUT_REF_AND_RESET(root_fc);
111
112 end:
113 bt_object_put_ref(fc);
114 return root_fc;
115 }
116
117 static
118 int create_meta(struct dmesg_component *dmesg_comp, bool has_ts)
119 {
120 struct bt_field_class *fc = NULL;
121 int ret = 0;
122
123 dmesg_comp->trace_class = bt_trace_class_create();
124 if (!dmesg_comp->trace_class) {
125 BT_LOGE_STR("Cannot create an empty trace class object.");
126 goto error;
127 }
128
129 dmesg_comp->stream_class = bt_stream_class_create(
130 dmesg_comp->trace_class);
131 if (!dmesg_comp->stream_class) {
132 BT_LOGE_STR("Cannot create a stream class object.");
133 goto error;
134 }
135
136 if (has_ts) {
137 dmesg_comp->clock_class = bt_clock_class_create();
138 if (!dmesg_comp->clock_class) {
139 BT_LOGE_STR("Cannot create clock class.");
140 goto error;
141 }
142
143 ret = bt_stream_class_set_default_clock_class(
144 dmesg_comp->stream_class, dmesg_comp->clock_class);
145 if (ret) {
146 BT_LOGE_STR("Cannot set stream class's default clock class.");
147 goto error;
148 }
149 }
150
151 dmesg_comp->event_class = bt_event_class_create(
152 dmesg_comp->stream_class);
153 if (!dmesg_comp->event_class) {
154 BT_LOGE_STR("Cannot create an event class object.");
155 goto error;
156 }
157
158 ret = bt_event_class_set_name(dmesg_comp->event_class, "string");
159 if (ret) {
160 BT_LOGE_STR("Cannot set event class's name.");
161 goto error;
162 }
163
164 fc = create_event_payload_fc();
165 if (!fc) {
166 BT_LOGE_STR("Cannot create event payload field class.");
167 goto error;
168 }
169
170 ret = bt_event_class_set_payload_field_class(dmesg_comp->event_class, fc);
171 if (ret) {
172 BT_LOGE_STR("Cannot set event class's event payload field class.");
173 goto error;
174 }
175
176 goto end;
177
178 error:
179 ret = -1;
180
181 end:
182 bt_object_put_ref(fc);
183 return ret;
184 }
185
186 static
187 int handle_params(struct dmesg_component *dmesg_comp,
188 const struct bt_value *params)
189 {
190 const struct bt_value *no_timestamp = NULL;
191 const struct bt_value *path = NULL;
192 const char *path_str;
193 int ret = 0;
194
195 no_timestamp = bt_value_map_borrow_entry_value_const(params,
196 "no-extract-timestamp");
197 if (no_timestamp) {
198 if (!bt_value_is_bool(no_timestamp)) {
199 BT_LOGE("Expecting a boolean value for the `no-extract-timestamp` parameter: "
200 "type=%s",
201 bt_common_value_type_string(
202 bt_value_get_type(no_timestamp)));
203 goto error;
204 }
205
206 dmesg_comp->params.no_timestamp =
207 bt_value_bool_get(no_timestamp);
208 }
209
210 path = bt_value_map_borrow_entry_value_const(params, "path");
211 if (path) {
212 if (dmesg_comp->params.read_from_stdin) {
213 BT_LOGE_STR("Cannot specify both `read-from-stdin` and `path` parameters.");
214 goto error;
215 }
216
217 if (!bt_value_is_string(path)) {
218 BT_LOGE("Expecting a string value for the `path` parameter: "
219 "type=%s",
220 bt_common_value_type_string(
221 bt_value_get_type(path)));
222 goto error;
223 }
224
225 path_str = bt_value_string_get(path);
226 g_string_assign(dmesg_comp->params.path, path_str);
227 } else {
228 dmesg_comp->params.read_from_stdin = true;
229 }
230
231 goto end;
232
233 error:
234 ret = -1;
235
236 end:
237 return ret;
238 }
239
240 static
241 int create_packet_and_stream_and_trace(struct dmesg_component *dmesg_comp)
242 {
243 int ret = 0;
244 const char *trace_name;
245 gchar *basename = NULL;
246
247 dmesg_comp->trace = bt_trace_create(dmesg_comp->trace_class);
248 if (!dmesg_comp->trace) {
249 BT_LOGE_STR("Cannot create trace object.");
250 goto error;
251 }
252
253 if (dmesg_comp->params.read_from_stdin) {
254 trace_name = "STDIN";
255 } else {
256 basename = g_path_get_basename(dmesg_comp->params.path->str);
257 BT_ASSERT(basename);
258
259 if (strcmp(basename, G_DIR_SEPARATOR_S) != 0 &&
260 strcmp(basename, ".") != 0) {
261 trace_name = basename;
262 }
263 }
264
265 if (trace_name) {
266 ret = bt_trace_set_name(dmesg_comp->trace, trace_name);
267 if (ret) {
268 BT_LOGE("Cannot set trace's name: name=\"%s\"",
269 trace_name);
270 goto error;
271 }
272 }
273
274 dmesg_comp->stream = bt_stream_create(dmesg_comp->stream_class,
275 dmesg_comp->trace);
276 if (!dmesg_comp->stream) {
277 BT_LOGE_STR("Cannot create stream object.");
278 goto error;
279 }
280
281 dmesg_comp->packet = bt_packet_create(dmesg_comp->stream);
282 if (!dmesg_comp->packet) {
283 BT_LOGE_STR("Cannot create packet object.");
284 goto error;
285 }
286
287 ret = bt_trace_make_static(dmesg_comp->trace);
288 if (ret) {
289 BT_LOGE_STR("Cannot make trace static.");
290 goto error;
291 }
292
293 goto end;
294
295 error:
296 ret = -1;
297
298 end:
299 if (basename) {
300 g_free(basename);
301 }
302
303 return ret;
304 }
305
306 static
307 int try_create_meta_stream_packet(struct dmesg_component *dmesg_comp,
308 bool has_ts)
309 {
310 int ret = 0;
311
312 if (dmesg_comp->trace) {
313 /* Already created */
314 goto end;
315 }
316
317 ret = create_meta(dmesg_comp, has_ts);
318 if (ret) {
319 BT_LOGE("Cannot create metadata objects: dmesg-comp-addr=%p",
320 dmesg_comp);
321 goto error;
322 }
323
324 ret = create_packet_and_stream_and_trace(dmesg_comp);
325 if (ret) {
326 BT_LOGE("Cannot create packet and stream objects: "
327 "dmesg-comp-addr=%p", dmesg_comp);
328 goto error;
329 }
330
331 goto end;
332
333 error:
334 ret = -1;
335
336 end:
337 return ret;
338 }
339
340 static
341 void destroy_dmesg_component(struct dmesg_component *dmesg_comp)
342 {
343 if (!dmesg_comp) {
344 return;
345 }
346
347 if (dmesg_comp->params.path) {
348 g_string_free(dmesg_comp->params.path, TRUE);
349 }
350
351 bt_object_put_ref(dmesg_comp->packet);
352 bt_object_put_ref(dmesg_comp->trace);
353 bt_object_put_ref(dmesg_comp->stream_class);
354 bt_object_put_ref(dmesg_comp->event_class);
355 bt_object_put_ref(dmesg_comp->stream);
356 bt_object_put_ref(dmesg_comp->clock_class);
357 g_free(dmesg_comp);
358 }
359
360 static
361 enum bt_self_component_status create_port(
362 struct bt_self_component_source *self_comp)
363 {
364 return bt_self_component_source_add_output_port(self_comp,
365 "out", NULL, NULL);
366 }
367
368 BT_HIDDEN
369 enum bt_self_component_status dmesg_init(
370 struct bt_self_component_source *self_comp,
371 struct bt_value *params, void *init_method_data)
372 {
373 int ret = 0;
374 struct dmesg_component *dmesg_comp = g_new0(struct dmesg_component, 1);
375 enum bt_self_component_status status = BT_SELF_COMPONENT_STATUS_OK;
376
377 if (!dmesg_comp) {
378 BT_LOGE_STR("Failed to allocate one dmesg component structure.");
379 goto error;
380 }
381
382 dmesg_comp->params.path = g_string_new(NULL);
383 if (!dmesg_comp->params.path) {
384 BT_LOGE_STR("Failed to allocate a GString.");
385 goto error;
386 }
387
388 ret = handle_params(dmesg_comp, params);
389 if (ret) {
390 BT_LOGE("Invalid parameters: comp-addr=%p", self_comp);
391 goto error;
392 }
393
394 if (!dmesg_comp->params.read_from_stdin &&
395 !g_file_test(dmesg_comp->params.path->str,
396 G_FILE_TEST_IS_REGULAR)) {
397 BT_LOGE("Input path is not a regular file: "
398 "comp-addr=%p, path=\"%s\"", self_comp,
399 dmesg_comp->params.path->str);
400 goto error;
401 }
402
403 status = create_port(self_comp);
404 if (status != BT_SELF_COMPONENT_STATUS_OK) {
405 goto error;
406 }
407
408 bt_self_component_set_data(
409 bt_self_component_source_as_self_component(self_comp),
410 dmesg_comp);
411 goto end;
412
413 error:
414 destroy_dmesg_component(dmesg_comp);
415 bt_self_component_set_data(
416 bt_self_component_source_as_self_component(self_comp),
417 NULL);
418
419 if (status >= 0) {
420 status = BT_SELF_COMPONENT_STATUS_ERROR;
421 }
422
423 end:
424 return status;
425 }
426
427 BT_HIDDEN
428 void dmesg_finalize(struct bt_self_component_source *self_comp)
429 {
430 destroy_dmesg_component(bt_self_component_get_data(
431 bt_self_component_source_as_self_component(self_comp)));
432 }
433
434 static
435 struct bt_notification *create_init_event_notif_from_line(
436 struct dmesg_notif_iter *notif_iter,
437 const char *line, const char **new_start)
438 {
439 struct bt_event *event;
440 struct bt_notification *notif = NULL;
441 bool has_timestamp = false;
442 unsigned long sec, usec, msec;
443 unsigned int year, mon, mday, hour, min;
444 uint64_t ts = 0;
445 int ret = 0;
446 struct dmesg_component *dmesg_comp = notif_iter->dmesg_comp;
447
448 *new_start = line;
449
450 if (dmesg_comp->params.no_timestamp) {
451 goto skip_ts;
452 }
453
454 /* Extract time from input line */
455 if (sscanf(line, "[%lu.%lu] ", &sec, &usec) == 2) {
456 ts = (uint64_t) sec * USEC_PER_SEC + (uint64_t) usec;
457
458 /*
459 * The clock class we use has a 1 GHz frequency: convert
460 * from µs to ns.
461 */
462 ts *= NSEC_PER_USEC;
463 has_timestamp = true;
464 } else if (sscanf(line, "[%u-%u-%u %u:%u:%lu.%lu] ",
465 &year, &mon, &mday, &hour, &min,
466 &sec, &msec) == 7) {
467 time_t ep_sec;
468 struct tm ti;
469
470 memset(&ti, 0, sizeof(ti));
471 ti.tm_year = year - 1900; /* From 1900 */
472 ti.tm_mon = mon - 1; /* 0 to 11 */
473 ti.tm_mday = mday;
474 ti.tm_hour = hour;
475 ti.tm_min = min;
476 ti.tm_sec = sec;
477
478 ep_sec = bt_timegm(&ti);
479 if (ep_sec != (time_t) -1) {
480 ts = (uint64_t) ep_sec * NSEC_PER_SEC
481 + (uint64_t) msec * NSEC_PER_MSEC;
482 }
483
484 has_timestamp = true;
485 }
486
487 if (has_timestamp) {
488 /* Set new start for the message portion of the line */
489 *new_start = strchr(line, ']');
490 BT_ASSERT(*new_start);
491 (*new_start)++;
492
493 if ((*new_start)[0] == ' ') {
494 (*new_start)++;
495 }
496 }
497
498 skip_ts:
499 /*
500 * At this point, we know if the stream class's event header
501 * field class should have a timestamp or not, so we can lazily
502 * create the metadata, stream, and packet objects.
503 */
504 ret = try_create_meta_stream_packet(dmesg_comp, has_timestamp);
505 if (ret) {
506 /* try_create_meta_stream_packet() logs errors */
507 goto error;
508 }
509
510 notif = bt_notification_event_create(notif_iter->pc_notif_iter,
511 dmesg_comp->event_class, dmesg_comp->packet);
512 if (!notif) {
513 BT_LOGE_STR("Cannot create event notification.");
514 goto error;
515 }
516
517 event = bt_notification_event_borrow_event(notif);
518 BT_ASSERT(event);
519
520 if (dmesg_comp->clock_class) {
521 bt_event_set_default_clock_value(event, ts);
522 }
523
524 goto end;
525
526 error:
527 BT_OBJECT_PUT_REF_AND_RESET(notif);
528
529 end:
530 return notif;
531 }
532
533 static
534 int fill_event_payload_from_line(const char *line,
535 struct bt_event *event)
536 {
537 struct bt_field *ep_field = NULL;
538 struct bt_field *str_field = NULL;
539 size_t len;
540 int ret;
541
542 ep_field = bt_event_borrow_payload_field(event);
543 BT_ASSERT(ep_field);
544 str_field = bt_field_structure_borrow_member_field_by_index(
545 ep_field, 0);
546 if (!str_field) {
547 BT_LOGE_STR("Cannot borrow `timestamp` field from event payload structure field.");
548 goto error;
549 }
550
551 len = strlen(line);
552 if (line[len - 1] == '\n') {
553 /* Do not include the newline character in the payload */
554 len--;
555 }
556
557 ret = bt_field_string_clear(str_field);
558 if (ret) {
559 BT_LOGE_STR("Cannot clear string field object.");
560 goto error;
561 }
562
563 ret = bt_field_string_append_with_length(str_field, line, len);
564 if (ret) {
565 BT_LOGE("Cannot append value to string field object: "
566 "len=%zu", len);
567 goto error;
568 }
569
570 goto end;
571
572 error:
573 ret = -1;
574
575 end:
576 return ret;
577 }
578
579 static
580 struct bt_notification *create_notif_from_line(
581 struct dmesg_notif_iter *dmesg_notif_iter, const char *line)
582 {
583 struct bt_event *event = NULL;
584 struct bt_notification *notif = NULL;
585 const char *new_start;
586 int ret;
587
588 notif = create_init_event_notif_from_line(dmesg_notif_iter,
589 line, &new_start);
590 if (!notif) {
591 BT_LOGE_STR("Cannot create and initialize event notification from line.");
592 goto error;
593 }
594
595 event = bt_notification_event_borrow_event(notif);
596 BT_ASSERT(event);
597 ret = fill_event_payload_from_line(new_start, event);
598 if (ret) {
599 BT_LOGE("Cannot fill event payload field from line: "
600 "ret=%d", ret);
601 goto error;
602 }
603
604 goto end;
605
606 error:
607 BT_OBJECT_PUT_REF_AND_RESET(notif);
608
609 end:
610 return notif;
611 }
612
613 static
614 void destroy_dmesg_notif_iter(struct dmesg_notif_iter *dmesg_notif_iter)
615 {
616 if (!dmesg_notif_iter) {
617 return;
618 }
619
620 if (dmesg_notif_iter->fp && dmesg_notif_iter->fp != stdin) {
621 if (fclose(dmesg_notif_iter->fp)) {
622 BT_LOGE_ERRNO("Cannot close input file", ".");
623 }
624 }
625
626 bt_object_put_ref(dmesg_notif_iter->tmp_event_notif);
627 free(dmesg_notif_iter->linebuf);
628 g_free(dmesg_notif_iter);
629 }
630
631 BT_HIDDEN
632 enum bt_self_notification_iterator_status dmesg_notif_iter_init(
633 struct bt_self_notification_iterator *self_notif_iter,
634 struct bt_self_component_source *self_comp,
635 struct bt_self_component_port_output *self_port)
636 {
637 struct dmesg_component *dmesg_comp;
638 struct dmesg_notif_iter *dmesg_notif_iter =
639 g_new0(struct dmesg_notif_iter, 1);
640 enum bt_self_notification_iterator_status status =
641 BT_SELF_NOTIFICATION_ITERATOR_STATUS_OK;
642
643 if (!dmesg_notif_iter) {
644 BT_LOGE_STR("Failed to allocate on dmesg notification iterator structure.");
645 goto error;
646 }
647
648 dmesg_comp = bt_self_component_get_data(
649 bt_self_component_source_as_self_component(self_comp));
650 BT_ASSERT(dmesg_comp);
651 dmesg_notif_iter->dmesg_comp = dmesg_comp;
652 dmesg_notif_iter->pc_notif_iter = self_notif_iter;
653
654 if (dmesg_comp->params.read_from_stdin) {
655 dmesg_notif_iter->fp = stdin;
656 } else {
657 dmesg_notif_iter->fp = fopen(dmesg_comp->params.path->str, "r");
658 if (!dmesg_notif_iter->fp) {
659 BT_LOGE_ERRNO("Cannot open input file in read mode", ": path=\"%s\"",
660 dmesg_comp->params.path->str);
661 goto error;
662 }
663 }
664
665 bt_self_notification_iterator_set_data(self_notif_iter,
666 dmesg_notif_iter);
667 goto end;
668
669 error:
670 destroy_dmesg_notif_iter(dmesg_notif_iter);
671 bt_self_notification_iterator_set_data(self_notif_iter, NULL);
672 if (status >= 0) {
673 status = BT_SELF_NOTIFICATION_ITERATOR_STATUS_ERROR;
674 }
675
676 end:
677 return status;
678 }
679
680 BT_HIDDEN
681 void dmesg_notif_iter_finalize(
682 struct bt_self_notification_iterator *priv_notif_iter)
683 {
684 destroy_dmesg_notif_iter(bt_self_notification_iterator_get_data(
685 priv_notif_iter));
686 }
687
688 static
689 enum bt_self_notification_iterator_status dmesg_notif_iter_next_one(
690 struct dmesg_notif_iter *dmesg_notif_iter,
691 struct bt_notification **notif)
692 {
693 ssize_t len;
694 struct dmesg_component *dmesg_comp;
695 enum bt_self_notification_iterator_status status =
696 BT_SELF_NOTIFICATION_ITERATOR_STATUS_OK;
697
698 BT_ASSERT(dmesg_notif_iter);
699 dmesg_comp = dmesg_notif_iter->dmesg_comp;
700 BT_ASSERT(dmesg_comp);
701
702 if (dmesg_notif_iter->state == STATE_DONE) {
703 status = BT_SELF_NOTIFICATION_ITERATOR_STATUS_END;
704 goto end;
705 }
706
707 if (dmesg_notif_iter->tmp_event_notif ||
708 dmesg_notif_iter->state == STATE_EMIT_PACKET_END ||
709 dmesg_notif_iter->state == STATE_EMIT_STREAM_END) {
710 goto handle_state;
711 }
712
713 while (true) {
714 const char *ch;
715 bool only_spaces = true;
716
717 len = bt_getline(&dmesg_notif_iter->linebuf,
718 &dmesg_notif_iter->linebuf_len, dmesg_notif_iter->fp);
719 if (len < 0) {
720 if (errno == EINVAL) {
721 status = BT_SELF_NOTIFICATION_ITERATOR_STATUS_ERROR;
722 } else if (errno == ENOMEM) {
723 status =
724 BT_SELF_NOTIFICATION_ITERATOR_STATUS_NOMEM;
725 } else {
726 if (dmesg_notif_iter->state == STATE_EMIT_STREAM_BEGINNING) {
727 /* Stream did not even begin */
728 status = BT_SELF_NOTIFICATION_ITERATOR_STATUS_END;
729 goto end;
730 } else {
731 /* End current packet now */
732 dmesg_notif_iter->state =
733 STATE_EMIT_PACKET_END;
734 goto handle_state;
735 }
736 }
737
738 goto end;
739 }
740
741 BT_ASSERT(dmesg_notif_iter->linebuf);
742
743 /* Ignore empty lines, once trimmed */
744 for (ch = dmesg_notif_iter->linebuf; *ch != '\0'; ch++) {
745 if (!isspace(*ch)) {
746 only_spaces = false;
747 break;
748 }
749 }
750
751 if (!only_spaces) {
752 break;
753 }
754 }
755
756 dmesg_notif_iter->tmp_event_notif = create_notif_from_line(
757 dmesg_notif_iter, dmesg_notif_iter->linebuf);
758 if (!dmesg_notif_iter->tmp_event_notif) {
759 BT_LOGE("Cannot create event notification from line: "
760 "dmesg-comp-addr=%p, line=\"%s\"", dmesg_comp,
761 dmesg_notif_iter->linebuf);
762 goto end;
763 }
764
765 handle_state:
766 BT_ASSERT(dmesg_comp->trace);
767
768 switch (dmesg_notif_iter->state) {
769 case STATE_EMIT_STREAM_BEGINNING:
770 BT_ASSERT(dmesg_notif_iter->tmp_event_notif);
771 *notif = bt_notification_stream_begin_create(
772 dmesg_notif_iter->pc_notif_iter, dmesg_comp->stream);
773 dmesg_notif_iter->state = STATE_EMIT_PACKET_BEGINNING;
774 break;
775 case STATE_EMIT_PACKET_BEGINNING:
776 BT_ASSERT(dmesg_notif_iter->tmp_event_notif);
777 *notif = bt_notification_packet_begin_create(
778 dmesg_notif_iter->pc_notif_iter, dmesg_comp->packet);
779 dmesg_notif_iter->state = STATE_EMIT_EVENT;
780 break;
781 case STATE_EMIT_EVENT:
782 BT_ASSERT(dmesg_notif_iter->tmp_event_notif);
783 *notif = dmesg_notif_iter->tmp_event_notif;
784 dmesg_notif_iter->tmp_event_notif = NULL;
785 break;
786 case STATE_EMIT_PACKET_END:
787 *notif = bt_notification_packet_end_create(
788 dmesg_notif_iter->pc_notif_iter, dmesg_comp->packet);
789 dmesg_notif_iter->state = STATE_EMIT_STREAM_END;
790 break;
791 case STATE_EMIT_STREAM_END:
792 *notif = bt_notification_stream_end_create(
793 dmesg_notif_iter->pc_notif_iter, dmesg_comp->stream);
794 dmesg_notif_iter->state = STATE_DONE;
795 break;
796 default:
797 break;
798 }
799
800 if (!*notif) {
801 BT_LOGE("Cannot create notification: dmesg-comp-addr=%p",
802 dmesg_comp);
803 status = BT_SELF_NOTIFICATION_ITERATOR_STATUS_ERROR;
804 }
805
806 end:
807 return status;
808 }
809
810 BT_HIDDEN
811 enum bt_self_notification_iterator_status dmesg_notif_iter_next(
812 struct bt_self_notification_iterator *self_notif_iter,
813 bt_notification_array_const notifs, uint64_t capacity,
814 uint64_t *count)
815 {
816 struct dmesg_notif_iter *dmesg_notif_iter =
817 bt_self_notification_iterator_get_data(
818 self_notif_iter);
819 enum bt_self_notification_iterator_status status =
820 BT_SELF_NOTIFICATION_ITERATOR_STATUS_OK;
821 uint64_t i = 0;
822
823 while (i < capacity &&
824 status == BT_SELF_NOTIFICATION_ITERATOR_STATUS_OK) {
825 struct bt_notification *priv_notif = NULL;
826
827 status = dmesg_notif_iter_next_one(dmesg_notif_iter,
828 &priv_notif);
829 notifs[i] = priv_notif;
830 if (status == BT_SELF_NOTIFICATION_ITERATOR_STATUS_OK) {
831 i++;
832 }
833 }
834
835 if (i > 0) {
836 /*
837 * Even if dmesg_notif_iter_next_one() returned
838 * something else than
839 * BT_SELF_NOTIFICATION_ITERATOR_STATUS_OK, we
840 * accumulated notification objects in the output
841 * notification array, so we need to return
842 * BT_SELF_NOTIFICATION_ITERATOR_STATUS_OK so that they
843 * are transfered to downstream. This other status
844 * occurs again the next time muxer_notif_iter_do_next()
845 * is called, possibly without any accumulated
846 * notification, in which case we'll return it.
847 */
848 *count = i;
849 status = BT_SELF_NOTIFICATION_ITERATOR_STATUS_OK;
850 }
851
852 return status;
853 }
This page took 0.055745 seconds and 4 git commands to generate.