diff options
Diffstat (limited to 'runtime/print_flush.c')
-rw-r--r-- | runtime/print_flush.c | 129 |
1 files changed, 129 insertions, 0 deletions
diff --git a/runtime/print_flush.c b/runtime/print_flush.c new file mode 100644 index 00000000..52017426 --- /dev/null +++ b/runtime/print_flush.c @@ -0,0 +1,129 @@ +/* -*- linux-c -*- + * Print Flush Function + * Copyright (C) 2007-2008 Red Hat Inc. + * + * This file is part of systemtap, and is free software. You can + * redistribute it and/or modify it under the terms of the GNU General + * Public License (GPL); either version 2, or (at your option) any + * later version. + */ + +/** Send the print buffer to the transport now. + * Output accumulates in the print buffer until it + * is filled, or this is called. This MUST be called before returning + * from a probe or accumulated output in the print buffer will be lost. + * + * @note Preemption must be disabled to use this. + */ + +static DEFINE_SPINLOCK(_stp_print_lock); + +void EXPORT_FN(stp_print_flush)(_stp_pbuf *pb) +{ + size_t len = pb->len; + void *entry = NULL; + + /* check to see if there is anything in the buffer */ + dbug_trans(1, "len = %zu\n", len); + if (likely(len == 0)) + return; + + pb->len = 0; + + if (unlikely(_stp_transport_get_state() != STP_TRANSPORT_RUNNING)) + return; + +#ifdef STP_BULKMODE +#ifdef NO_PERCPU_HEADERS + { + char *bufp = pb->buf; + + while (len > 0) { + size_t bytes_reserved; + + bytes_reserved = _stp_data_write_reserve(len, &entry); + if (likely(entry && bytes_reserved > 0)) { + memcpy(_stp_data_entry_data(entry), bufp, + bytes_reserved); + _stp_data_write_commit(entry); + bufp += bytes_reserved; + len -= bytes_reserved; + } + else { + atomic_inc(&_stp_transport_failures); + break; + } + } + } + +#else /* !NO_PERCPU_HEADERS */ + + { + char *bufp = pb->buf; + struct _stp_trace t = { .sequence = _stp_seq_inc(), + .pdu_len = len}; + size_t bytes_reserved; + + bytes_reserved = _stp_data_write_reserve(sizeof(struct _stp_trace), &entry); + if (likely(entry && bytes_reserved > 0)) { + /* prevent unaligned access by using memcpy() */ + memcpy(_stp_data_entry_data(entry), &t, sizeof(t)); + _stp_data_write_commit(entry); + } + else { + atomic_inc(&_stp_transport_failures); + return; + } + + while (len > 0) { + bytes_reserved = _stp_data_write_reserve(len, &entry); + if (likely(entry && bytes_reserved > 0)) { + memcpy(_stp_data_entry_data(entry), bufp, + bytes_reserved); + _stp_data_write_commit(entry); + bufp += bytes_reserved; + len -= bytes_reserved; + } + else { + atomic_inc(&_stp_transport_failures); + break; + } + } + } +#endif /* !NO_PERCPU_HEADERS */ + +#else /* !STP_BULKMODE */ + +#if STP_TRANSPORT_VERSION == 1 + + if (unlikely(_stp_ctl_write(STP_REALTIME_DATA, pb->buf, len) <= 0)) + atomic_inc (&_stp_transport_failures); + +#else /* STP_TRANSPORT_VERSION != 1 */ + { + unsigned long flags; + char *bufp = pb->buf; + + dbug_trans(1, "calling _stp_data_write...\n"); + spin_lock_irqsave(&_stp_print_lock, flags); + while (len > 0) { + size_t bytes_reserved; + + bytes_reserved = _stp_data_write_reserve(len, &entry); + if (likely(entry && bytes_reserved > 0)) { + memcpy(_stp_data_entry_data(entry), bufp, + bytes_reserved); + _stp_data_write_commit(entry); + bufp += bytes_reserved; + len -= bytes_reserved; + } + else { + atomic_inc(&_stp_transport_failures); + break; + } + } + spin_unlock_irqrestore(&_stp_print_lock, flags); + } +#endif /* STP_TRANSPORT_VERSION != 1 */ +#endif /* !STP_BULKMODE */ +} |