4 * Babeltrace CTF Writer Output Plugin Event Handling
6 * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
8 * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
10 * Permission is hereby granted, free of charge, to any person obtaining a copy
11 * of this software and associated documentation files (the "Software"), to deal
12 * in the Software without restriction, including without limitation the rights
13 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 * copies of the Software, and to permit persons to whom the Software is
15 * furnished to do so, subject to the following conditions:
17 * The above copyright notice and this permission notice shall be included in
18 * all copies or substantial portions of the Software.
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29 #include <babeltrace/ctf-ir/event.h>
30 #include <babeltrace/ctf-ir/packet.h>
31 #include <babeltrace/ctf-ir/event-class.h>
32 #include <babeltrace/ctf-ir/stream.h>
33 #include <babeltrace/ctf-ir/stream-class.h>
34 #include <babeltrace/ctf-ir/clock-class.h>
35 #include <babeltrace/ctf-ir/fields.h>
36 #include <babeltrace/ctf-writer/stream-class.h>
37 #include <babeltrace/ctf-writer/stream.h>
40 #include <ctfcopytrace.h>
45 void unref_stream_class(struct bt_ctf_stream_class
*writer_stream_class
)
47 bt_put(writer_stream_class
);
51 void unref_stream(struct bt_ctf_stream_class
*writer_stream
)
53 bt_put(writer_stream
);
56 gboolean
empty_ht(gpointer key
, gpointer value
, gpointer user_data
)
61 void destroy_stream_state_key(gpointer key
)
63 g_free((enum fs_writer_stream_state
*) key
);
66 void check_completed_trace(gpointer key
, gpointer value
, gpointer user_data
)
68 enum fs_writer_stream_state
*state
= value
;
69 int *trace_completed
= user_data
;
71 if (*state
!= FS_WRITER_COMPLETED_STREAM
) {
77 void trace_is_static_listener(struct bt_ctf_trace
*trace
, void *data
)
79 struct fs_writer
*fs_writer
= data
;
80 int trace_completed
= 1;
82 fs_writer
->trace_static
= 1;
84 g_hash_table_foreach(fs_writer
->stream_states
,
85 check_completed_trace
, &trace_completed
);
86 if (trace_completed
) {
87 writer_close(fs_writer
->writer_component
, fs_writer
);
88 g_hash_table_remove(fs_writer
->writer_component
->trace_map
,
94 struct bt_ctf_stream_class
*insert_new_stream_class(
95 struct writer_component
*writer_component
,
96 struct fs_writer
*fs_writer
,
97 struct bt_ctf_stream_class
*stream_class
)
99 struct bt_ctf_stream_class
*writer_stream_class
= NULL
;
100 struct bt_ctf_trace
*trace
= NULL
, *writer_trace
= NULL
;
101 struct bt_ctf_writer
*ctf_writer
= fs_writer
->writer
;
102 enum bt_component_status ret
;
104 trace
= bt_ctf_stream_class_get_trace(stream_class
);
106 fprintf(writer_component
->err
,
107 "[error] %s in %s:%d\n", __func__
, __FILE__
,
112 writer_trace
= bt_ctf_writer_get_trace(ctf_writer
);
114 fprintf(writer_component
->err
,
115 "[error] %s in %s:%d\n", __func__
, __FILE__
,
120 ret
= ctf_copy_clock_classes(writer_component
->err
, writer_trace
,
121 writer_stream_class
, trace
);
122 if (ret
!= BT_COMPONENT_STATUS_OK
) {
123 fprintf(writer_component
->err
,
124 "[error] %s in %s:%d\n", __func__
, __FILE__
,
129 writer_stream_class
= ctf_copy_stream_class(writer_component
->err
,
130 stream_class
, writer_trace
, true);
131 if (!writer_stream_class
) {
132 fprintf(writer_component
->err
, "[error] Failed to copy stream class\n");
133 fprintf(writer_component
->err
, "[error] %s in %s:%d\n",
134 __func__
, __FILE__
, __LINE__
);
138 g_hash_table_insert(fs_writer
->stream_class_map
,
139 (gpointer
) stream_class
, writer_stream_class
);
144 BT_PUT(writer_stream_class
);
146 bt_put(writer_trace
);
148 return writer_stream_class
;
152 enum fs_writer_stream_state
*insert_new_stream_state(
153 struct writer_component
*writer_component
,
154 struct fs_writer
*fs_writer
, struct bt_ctf_stream
*stream
)
156 enum fs_writer_stream_state
*v
= NULL
;
158 v
= g_new0(enum fs_writer_stream_state
, 1);
160 fprintf(writer_component
->err
,
161 "[error] %s in %s:%d\n", __func__
,
164 *v
= FS_WRITER_UNKNOWN_STREAM
;
166 g_hash_table_insert(fs_writer
->stream_states
, stream
, v
);
172 int make_trace_path(struct writer_component
*writer_component
,
173 struct bt_ctf_trace
*trace
, char *trace_path
)
176 const char *trace_name
;
178 trace_name
= bt_ctf_trace_get_name(trace
);
180 trace_name
= writer_component
->trace_name_base
->str
;
182 /* XXX: we might have to skip the first level, TBD. */
184 /* Sanitize the trace name. */
185 if (strlen(trace_name
) == 2 && !strcmp(trace_name
, "..")) {
186 fprintf(writer_component
->err
, "[error] Trace name cannot "
191 if (strstr(trace_name
, "../")) {
192 fprintf(writer_component
->err
, "[error] Trace name cannot "
193 "contain \"../\", received \"%s\"\n",
199 snprintf(trace_path
, PATH_MAX
, "%s/%s",
200 writer_component
->base_path
->str
,
202 if (g_file_test(trace_path
, G_FILE_TEST_EXISTS
)) {
205 snprintf(trace_path
, PATH_MAX
, "%s/%s-%d",
206 writer_component
->base_path
->str
,
208 } while (g_file_test(trace_path
, G_FILE_TEST_EXISTS
) && i
< INT_MAX
);
210 fprintf(writer_component
->err
, "[error] Unable to find "
211 "a unique trace path\n");
227 struct fs_writer
*insert_new_writer(
228 struct writer_component
*writer_component
,
229 struct bt_ctf_trace
*trace
)
231 struct bt_ctf_writer
*ctf_writer
= NULL
;
232 struct bt_ctf_trace
*writer_trace
= NULL
;
233 char trace_path
[PATH_MAX
];
234 enum bt_component_status ret
;
235 struct bt_ctf_stream
*stream
= NULL
;
236 struct fs_writer
*fs_writer
= NULL
;
239 ret
= make_trace_path(writer_component
, trace
, trace_path
);
241 fprintf(writer_component
->err
, "[error] %s in %s:%d\n",
242 __func__
, __FILE__
, __LINE__
);
246 printf("ctf.fs sink creating trace in %s\n", trace_path
);
248 ctf_writer
= bt_ctf_writer_create(trace_path
);
250 fprintf(writer_component
->err
, "[error] %s in %s:%d\n",
251 __func__
, __FILE__
, __LINE__
);
255 writer_trace
= bt_ctf_writer_get_trace(ctf_writer
);
257 fprintf(writer_component
->err
,
258 "[error] %s in %s:%d\n", __func__
, __FILE__
,
263 ret
= ctf_copy_trace(writer_component
->err
, trace
, writer_trace
);
264 if (ret
!= BT_COMPONENT_STATUS_OK
) {
265 fprintf(writer_component
->err
, "[error] Failed to copy trace\n");
266 fprintf(writer_component
->err
, "[error] %s in %s:%d\n",
267 __func__
, __FILE__
, __LINE__
);
272 fs_writer
= g_new0(struct fs_writer
, 1);
274 fprintf(writer_component
->err
,
275 "[error] %s in %s:%d\n", __func__
, __FILE__
,
279 fs_writer
->writer
= ctf_writer
;
280 fs_writer
->trace
= trace
;
281 fs_writer
->writer_trace
= writer_trace
;
282 fs_writer
->writer_component
= writer_component
;
283 BT_PUT(writer_trace
);
284 fs_writer
->stream_class_map
= g_hash_table_new_full(g_direct_hash
,
285 g_direct_equal
, NULL
, (GDestroyNotify
) unref_stream_class
);
286 fs_writer
->stream_map
= g_hash_table_new_full(g_direct_hash
,
287 g_direct_equal
, NULL
, (GDestroyNotify
) unref_stream
);
288 fs_writer
->stream_states
= g_hash_table_new_full(g_direct_hash
,
289 g_direct_equal
, NULL
, destroy_stream_state_key
);
291 /* Set all the existing streams in the unknown state. */
292 nr_stream
= bt_ctf_trace_get_stream_count(trace
);
293 for (i
= 0; i
< nr_stream
; i
++) {
294 stream
= bt_ctf_trace_get_stream_by_index(trace
, i
);
296 fprintf(writer_component
->err
,
297 "[error] %s in %s:%d\n", __func__
,
301 insert_new_stream_state(writer_component
, fs_writer
, stream
);
305 /* Check if the trace is already static or register a listener. */
306 if (bt_ctf_trace_is_static(trace
)) {
307 fs_writer
->trace_static
= 1;
308 fs_writer
->static_listener_id
= -1;
310 ret
= bt_ctf_trace_add_is_static_listener(trace
,
311 trace_is_static_listener
, fs_writer
);
313 fprintf(writer_component
->err
,
314 "[error] %s in %s:%d\n", __func__
, __FILE__
,
318 fs_writer
->static_listener_id
= ret
;
321 g_hash_table_insert(writer_component
->trace_map
, (gpointer
) trace
,
329 bt_put(writer_trace
);
337 struct fs_writer
*get_fs_writer(struct writer_component
*writer_component
,
338 struct bt_ctf_stream_class
*stream_class
)
340 struct bt_ctf_trace
*trace
= NULL
;
341 struct fs_writer
*fs_writer
;
343 trace
= bt_ctf_stream_class_get_trace(stream_class
);
345 fprintf(writer_component
->err
, "[error] %s in %s:%d\n",
346 __func__
, __FILE__
, __LINE__
);
350 fs_writer
= g_hash_table_lookup(writer_component
->trace_map
,
353 fs_writer
= insert_new_writer(writer_component
, trace
);
365 struct fs_writer
*get_fs_writer_from_stream(
366 struct writer_component
*writer_component
,
367 struct bt_ctf_stream
*stream
)
369 struct bt_ctf_stream_class
*stream_class
= NULL
;
370 struct fs_writer
*fs_writer
;
372 stream_class
= bt_ctf_stream_get_class(stream
);
374 fprintf(writer_component
->err
, "[error] %s in %s:%d\n",
375 __func__
, __FILE__
, __LINE__
);
379 fs_writer
= get_fs_writer(writer_component
, stream_class
);
386 bt_put(stream_class
);
391 struct bt_ctf_stream_class
*lookup_stream_class(
392 struct writer_component
*writer_component
,
393 struct bt_ctf_stream_class
*stream_class
)
395 struct fs_writer
*fs_writer
= get_fs_writer(
396 writer_component
, stream_class
);
398 return (struct bt_ctf_stream_class
*) g_hash_table_lookup(
399 fs_writer
->stream_class_map
, (gpointer
) stream_class
);
403 struct bt_ctf_stream
*lookup_stream(struct writer_component
*writer_component
,
404 struct bt_ctf_stream
*stream
)
406 struct fs_writer
*fs_writer
= get_fs_writer_from_stream(
407 writer_component
, stream
);
409 return (struct bt_ctf_stream
*) g_hash_table_lookup(
410 fs_writer
->stream_map
, (gpointer
) stream
);
414 struct bt_ctf_stream
*insert_new_stream(
415 struct writer_component
*writer_component
,
416 struct fs_writer
*fs_writer
,
417 struct bt_ctf_stream_class
*stream_class
,
418 struct bt_ctf_stream
*stream
)
420 struct bt_ctf_stream
*writer_stream
= NULL
;
421 struct bt_ctf_stream_class
*writer_stream_class
= NULL
;
422 struct bt_ctf_writer
*ctf_writer
= bt_get(fs_writer
->writer
);
424 writer_stream_class
= lookup_stream_class(writer_component
,
426 if (!writer_stream_class
) {
427 writer_stream_class
= insert_new_stream_class(
428 writer_component
, fs_writer
, stream_class
);
429 if (!writer_stream_class
) {
430 fprintf(writer_component
->err
, "[error] %s in %s:%d\n",
431 __func__
, __FILE__
, __LINE__
);
435 bt_get(writer_stream_class
);
437 writer_stream
= bt_ctf_writer_create_stream(ctf_writer
,
438 writer_stream_class
);
439 if (!writer_stream
) {
440 fprintf(writer_component
->err
, "[error] %s in %s:%d\n",
441 __func__
, __FILE__
, __LINE__
);
445 g_hash_table_insert(fs_writer
->stream_map
, (gpointer
) stream
,
451 BT_PUT(writer_stream
);
454 bt_put(writer_stream_class
);
455 return writer_stream
;
459 struct bt_ctf_event_class
*get_event_class(struct writer_component
*writer_component
,
460 struct bt_ctf_stream_class
*writer_stream_class
,
461 struct bt_ctf_event_class
*event_class
)
463 return bt_ctf_stream_class_get_event_class_by_id(writer_stream_class
,
464 bt_ctf_event_class_get_id(event_class
));
468 struct bt_ctf_stream
*get_writer_stream(
469 struct writer_component
*writer_component
,
470 struct bt_ctf_packet
*packet
, struct bt_ctf_stream
*stream
)
472 struct bt_ctf_stream
*writer_stream
= NULL
;
474 writer_stream
= lookup_stream(writer_component
, stream
);
475 if (!writer_stream
) {
476 fprintf(writer_component
->err
, "[error] %s in %s:%d\n",
477 __func__
, __FILE__
, __LINE__
);
480 bt_get(writer_stream
);
485 BT_PUT(writer_stream
);
487 return writer_stream
;
491 void writer_close(struct writer_component
*writer_component
,
492 struct fs_writer
*fs_writer
)
494 if (fs_writer
->static_listener_id
> 0) {
495 bt_ctf_trace_remove_is_static_listener(fs_writer
->trace
,
496 fs_writer
->static_listener_id
);
499 /* Empty the stream class HT. */
500 g_hash_table_foreach_remove(fs_writer
->stream_class_map
,
502 g_hash_table_destroy(fs_writer
->stream_class_map
);
504 /* Empty the stream HT. */
505 g_hash_table_foreach_remove(fs_writer
->stream_map
,
507 g_hash_table_destroy(fs_writer
->stream_map
);
509 /* Empty the stream state HT. */
510 g_hash_table_foreach_remove(fs_writer
->stream_states
,
512 g_hash_table_destroy(fs_writer
->stream_states
);
516 enum bt_component_status
writer_stream_begin(
517 struct writer_component
*writer_component
,
518 struct bt_ctf_stream
*stream
)
520 struct bt_ctf_stream_class
*stream_class
= NULL
;
521 struct fs_writer
*fs_writer
;
522 struct bt_ctf_stream
*writer_stream
= NULL
;
523 enum bt_component_status ret
= BT_COMPONENT_STATUS_OK
;
524 enum fs_writer_stream_state
*state
;
526 stream_class
= bt_ctf_stream_get_class(stream
);
528 fprintf(writer_component
->err
, "[error] %s in %s:%d\n",
529 __func__
, __FILE__
, __LINE__
);
533 fs_writer
= get_fs_writer(writer_component
, stream_class
);
535 fprintf(writer_component
->err
, "[error] %s in %s:%d\n",
536 __func__
, __FILE__
, __LINE__
);
540 /* Set the stream as active */
541 state
= g_hash_table_lookup(fs_writer
->stream_states
, stream
);
543 if (fs_writer
->trace_static
) {
544 fprintf(writer_component
->err
, "[error] Adding a new "
545 "stream on a static trace\n");
548 state
= insert_new_stream_state(writer_component
, fs_writer
,
551 if (*state
!= FS_WRITER_UNKNOWN_STREAM
) {
552 fprintf(writer_component
->err
, "[error] Unexpected stream "
553 "state %d\n", *state
);
556 *state
= FS_WRITER_ACTIVE_STREAM
;
558 writer_stream
= insert_new_stream(writer_component
, fs_writer
,
559 stream_class
, stream
);
560 if (!writer_stream
) {
561 fprintf(writer_component
->err
, "[error] %s in %s:%d\n",
562 __func__
, __FILE__
, __LINE__
);
565 fs_writer
->active_streams
++;
570 ret
= BT_COMPONENT_STATUS_ERROR
;
572 bt_put(stream_class
);
577 enum bt_component_status
writer_stream_end(
578 struct writer_component
*writer_component
,
579 struct bt_ctf_stream
*stream
)
581 struct bt_ctf_stream_class
*stream_class
= NULL
;
582 struct fs_writer
*fs_writer
;
583 struct bt_ctf_trace
*trace
= NULL
;
584 enum bt_component_status ret
= BT_COMPONENT_STATUS_OK
;
585 enum fs_writer_stream_state
*state
;
587 stream_class
= bt_ctf_stream_get_class(stream
);
589 fprintf(writer_component
->err
, "[error] %s in %s:%d\n",
590 __func__
, __FILE__
, __LINE__
);
594 fs_writer
= get_fs_writer(writer_component
, stream_class
);
596 fprintf(writer_component
->err
, "[error] %s in %s:%d\n",
597 __func__
, __FILE__
, __LINE__
);
601 state
= g_hash_table_lookup(fs_writer
->stream_states
, stream
);
602 if (*state
!= FS_WRITER_ACTIVE_STREAM
) {
603 fprintf(writer_component
->err
, "[error] Unexpected stream "
604 "state %d\n", *state
);
607 *state
= FS_WRITER_COMPLETED_STREAM
;
609 g_hash_table_remove(fs_writer
->stream_map
, stream
);
611 if (fs_writer
->trace_static
) {
612 int trace_completed
= 1;
614 g_hash_table_foreach(fs_writer
->stream_states
,
615 check_completed_trace
, &trace_completed
);
616 if (trace_completed
) {
617 writer_close(writer_component
, fs_writer
);
618 g_hash_table_remove(writer_component
->trace_map
,
626 ret
= BT_COMPONENT_STATUS_ERROR
;
629 BT_PUT(stream_class
);
634 enum bt_component_status
writer_new_packet(
635 struct writer_component
*writer_component
,
636 struct bt_ctf_packet
*packet
)
638 struct bt_ctf_stream
*stream
= NULL
, *writer_stream
= NULL
;
639 struct bt_ctf_field
*writer_packet_context
= NULL
;
640 enum bt_component_status ret
= BT_COMPONENT_STATUS_OK
;
643 stream
= bt_ctf_packet_get_stream(packet
);
645 fprintf(writer_component
->err
, "[error] %s in %s:%d\n",
646 __func__
, __FILE__
, __LINE__
);
650 writer_stream
= get_writer_stream(writer_component
, packet
, stream
);
651 if (!writer_stream
) {
652 fprintf(writer_component
->err
, "[error] %s in %s:%d\n",
653 __func__
, __FILE__
, __LINE__
);
658 writer_packet_context
= ctf_copy_packet_context(writer_component
->err
,
659 packet
, writer_stream
);
660 if (!writer_packet_context
) {
661 fprintf(writer_component
->err
, "[error] %s in %s:%d\n",
662 __func__
, __FILE__
, __LINE__
);
666 int_ret
= bt_ctf_stream_set_packet_context(writer_stream
,
667 writer_packet_context
);
669 fprintf(writer_component
->err
, "[error] %s in %s:%d\n", __func__
,
673 BT_PUT(writer_stream
);
674 BT_PUT(writer_packet_context
);
679 ret
= BT_COMPONENT_STATUS_ERROR
;
681 bt_put(writer_stream
);
682 bt_put(writer_packet_context
);
688 enum bt_component_status
writer_close_packet(
689 struct writer_component
*writer_component
,
690 struct bt_ctf_packet
*packet
)
692 struct bt_ctf_stream
*stream
= NULL
, *writer_stream
= NULL
;
693 enum bt_component_status ret
;
695 stream
= bt_ctf_packet_get_stream(packet
);
697 fprintf(writer_component
->err
, "[error] %s in %s:%d\n",
698 __func__
, __FILE__
, __LINE__
);
702 writer_stream
= lookup_stream(writer_component
, stream
);
703 if (!writer_stream
) {
704 fprintf(writer_component
->err
, "[error] %s in %s:%d\n",
705 __func__
, __FILE__
, __LINE__
);
710 bt_get(writer_stream
);
712 ret
= bt_ctf_stream_flush(writer_stream
);
714 fprintf(writer_component
->err
,
715 "[error] Failed to flush packet\n");
718 BT_PUT(writer_stream
);
720 ret
= BT_COMPONENT_STATUS_OK
;
724 ret
= BT_COMPONENT_STATUS_ERROR
;
726 bt_put(writer_stream
);
732 enum bt_component_status
writer_output_event(
733 struct writer_component
*writer_component
,
734 struct bt_ctf_event
*event
)
736 enum bt_component_status ret
;
737 struct bt_ctf_event_class
*event_class
= NULL
, *writer_event_class
= NULL
;
738 struct bt_ctf_stream
*stream
= NULL
, *writer_stream
= NULL
;
739 struct bt_ctf_stream_class
*stream_class
= NULL
, *writer_stream_class
= NULL
;
740 struct bt_ctf_event
*writer_event
= NULL
;
741 const char *event_name
;
744 event_class
= bt_ctf_event_get_class(event
);
746 fprintf(writer_component
->err
, "[error] %s in %s:%d\n", __func__
,
751 event_name
= bt_ctf_event_class_get_name(event_class
);
753 fprintf(writer_component
->err
, "[error] %s in %s:%d\n", __func__
,
758 stream
= bt_ctf_event_get_stream(event
);
760 fprintf(writer_component
->err
, "[error] %s in %s:%d\n", __func__
,
765 writer_stream
= lookup_stream(writer_component
, stream
);
766 if (!writer_stream
|| !bt_get(writer_stream
)) {
767 fprintf(writer_component
->err
, "[error] %s in %s:%d\n", __func__
,
772 stream_class
= bt_ctf_event_class_get_stream_class(event_class
);
774 fprintf(writer_component
->err
, "[error] %s in %s:%d\n", __func__
,
779 writer_stream_class
= lookup_stream_class(writer_component
, stream_class
);
780 if (!writer_stream_class
|| !bt_get(writer_stream_class
)) {
781 fprintf(writer_component
->err
, "[error] %s in %s:%d\n", __func__
,
786 writer_event_class
= get_event_class(writer_component
,
787 writer_stream_class
, event_class
);
788 if (!writer_event_class
) {
789 writer_event_class
= ctf_copy_event_class(writer_component
->err
,
791 if (!writer_event_class
) {
792 fprintf(writer_component
->err
, "[error] %s in %s:%d\n",
793 __func__
, __FILE__
, __LINE__
);
796 int_ret
= bt_ctf_stream_class_add_event_class(
797 writer_stream_class
, writer_event_class
);
799 fprintf(writer_component
->err
, "[error] %s in %s:%d\n",
800 __func__
, __FILE__
, __LINE__
);
805 writer_event
= ctf_copy_event(writer_component
->err
, event
,
806 writer_event_class
, true);
808 fprintf(writer_component
->err
, "[error] %s in %s:%d\n", __func__
,
810 fprintf(writer_component
->err
, "[error] Failed to copy event %s\n",
811 bt_ctf_event_class_get_name(writer_event_class
));
815 int_ret
= bt_ctf_stream_append_event(writer_stream
, writer_event
);
817 fprintf(writer_component
->err
, "[error] %s in %s:%d\n", __func__
,
819 fprintf(writer_component
->err
, "[error] Failed to append event %s\n",
820 bt_ctf_event_class_get_name(writer_event_class
));
824 ret
= BT_COMPONENT_STATUS_OK
;
828 ret
= BT_COMPONENT_STATUS_ERROR
;
830 bt_put(writer_event
);
831 bt_put(writer_event_class
);
832 bt_put(writer_stream_class
);
833 bt_put(stream_class
);
834 bt_put(writer_stream
);