On 05.09.19 12:39, Janosch Frank wrote: > Linemode seems to add a newline for each sent message which makes > reading rather hard. Hence we add a small buffer and only print if > it's full or a newline is encountered. Except for when the string is > longer than the buffer, then we flush the buffer and print directly. > > Signed-off-by: Janosch Frank <frankja@xxxxxxxxxxxxx> > Reviewed-by: Thomas Huth <thuth@xxxxxxxxxx> > --- > lib/s390x/sclp-console.c | 70 +++++++++++++++++++++++++++++++++++++--- > 1 file changed, 66 insertions(+), 4 deletions(-) > > diff --git a/lib/s390x/sclp-console.c b/lib/s390x/sclp-console.c > index 19416b5..7397dc1 100644 > --- a/lib/s390x/sclp-console.c > +++ b/lib/s390x/sclp-console.c > @@ -13,6 +13,7 @@ > #include <asm/page.h> > #include <asm/arch_def.h> > #include <asm/io.h> > +#include <asm/spinlock.h> > #include "sclp.h" > > /* > @@ -87,6 +88,10 @@ static uint8_t _ascebc[256] = { > 0x90, 0x3F, 0x3F, 0x3F, 0x3F, 0xEA, 0x3F, 0xFF > }; > > +static char lm_buff[120]; Just wondering, how did you come up with the 120? (my first guess would have been something around 80) > +static unsigned char lm_buff_off; > +static struct spinlock lm_buff_lock; > + > static void sclp_print_ascii(const char *str) > { > int len = strlen(str); > @@ -103,10 +108,10 @@ static void sclp_print_ascii(const char *str) > sclp_service_call(SCLP_CMD_WRITE_EVENT_DATA, sccb); > } > > -static void sclp_print_lm(const char *str) > +static void lm_print(const char *buff, int len) > { The rename of str->buff could have been avoided, however, the impact is rather small. > unsigned char *ptr, *end, ch; > - unsigned int count, offset, len; > + unsigned int count, offset; > struct WriteEventData *sccb; > struct mdb *mdb; > struct mto *mto; > @@ -117,11 +122,10 @@ static void sclp_print_lm(const char *str) > end = (unsigned char *) sccb + 4096 - 1; > memset(sccb, 0, sizeof(*sccb)); > ptr = (unsigned char *) &sccb->msg.mdb.mto; > - len = strlen(str); > offset = 0; > do { > for (count = sizeof(*mto); offset < len; count++) { > - ch = str[offset++]; > + ch = buff[offset++]; > if (ch == 0x0a || ptr + count > end) > break; > ptr[count] = _ascebc[ch]; > @@ -148,6 +152,64 @@ static void sclp_print_lm(const char *str) > sclp_service_call(SCLP_CMD_WRITE_EVENT_DATA, sccb); > } > > + > +/* > + * In contrast to the ascii console, linemode produces a new > + * line with every write of data. The report() function uses > + * several printf() calls to generate a line of data which > + * would all end up on different lines. > + * > + * Hence we buffer here until we encounter a \n or the buffer > + * is full. That means that linemode output can look a bit > + * different from ascii and that it takes a bit longer for > + * lines to appear. > + */ > +static void sclp_print_lm(const char *str) > +{ > + int len; > + char *nl; > + > + spin_lock(&lm_buff_lock); > + > + len = strlen(str); You could do that directly when declaring the variable, doesn't have to be under the lock. > + /* > + * No use in copying into lm_buff, its time to flush the > + * buffer and print str until finished. > + */ > + if (len > sizeof(lm_buff)) { I find ARRAY_SIZE(lm_buf) easier to understand than sizeof(lm_buff) > + if (lm_buff_off) > + lm_print(lm_buff, lm_buff_off); > + lm_print(str, len); > + memset(lm_buff, 0 , sizeof(lm_buff)); > + lm_buff_off = 0; > + goto out; > + } > + > +fill: Is there a way to remove this goto by using a simple while loop? > + len = len < (sizeof(lm_buff) - lm_buff_off) ? len : (sizeof(lm_buff) - lm_buff_off); > + if ((lm_buff_off < sizeof(lm_buff) - 1)) { Drop one set of () > + memcpy(&lm_buff[lm_buff_off], str, len); > + lm_buff_off += len; > + } > + /* Buffer not full and no newline */ > + nl = strchr(lm_buff, '\n'); Why do we have to search? Shouldn't a newline be the last copied character only? > + if (lm_buff_off != sizeof(lm_buff) - 1 && !nl) > + goto out; > + > + lm_print(lm_buff, lm_buff_off); > + memset(lm_buff, 0 , sizeof(lm_buff)); > + lm_buff_off = 0; > + > + if (len < strlen(str)) { > + str = &str[len]; > + len = strlen(str); > + goto fill; > + } This looks too complicated for my taste :) Or my caffeine level is low. I think we have the following cases: 1. String contains newline a) String fits into remaining buffer -> Copy into buffer, flush (last character is newline) b) String doesn't fit into remaining buffer -> Simply flush old buffer and print remaining string? 2. String doesn't contain newline. a) String fits into remaining buffer -> Copy into buffer, flush if full b) String doesn't fit into remaining buffer -> Simply flush old buffer and print remaining string? Optimizing for 1b) or 2b) isn't really worth it I guess - unless we want to wrap *any* string at 120 characters. But then, your pre-loop handling would also have to be modified. I think this allow to simplify your code a lot. (how often does it happen in our current tests that we exceed 120 characters?) > + > +out: > + spin_unlock(&lm_buff_lock); > +} > + > /* > * SCLP needs to be initialized by setting a send and receive mask, > * indicating which messages the control program (we) want(s) to > -- Thanks, David / dhildenb