L4Re/departure

tests/dstest_pipe_client.cc

350:7ac27a50d236
2022-06-05 Paul Boddie Removed buffer register restoration from ipc_message_expect, adding it to ipc_message_wait. mmap-region-flags
     1 /*     2  * Test pipe operations.     3  *     4  * Copyright (C) 2020, 2021 Paul Boddie <paul@boddie.org.uk>     5  *     6  * This program is free software; you can redistribute it and/or     7  * modify it under the terms of the GNU General Public License as     8  * published by the Free Software Foundation; either version 2 of     9  * the License, or (at your option) any later version.    10  *    11  * This program is distributed in the hope that it will be useful,    12  * but WITHOUT ANY WARRANTY; without even the implied warranty of    13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    14  * GNU General Public License for more details.    15  *    16  * You should have received a copy of the GNU General Public License    17  * along with this program; if not, write to the Free Software    18  * Foundation, Inc., 51 Franklin Street, Fifth Floor,    19  * Boston, MA  02110-1301, USA    20  */    21     22 #include <l4/re/env.h>    23 #include <l4/sys/err.h>    24     25 #include <thread>    26     27 #include <stdio.h>    28 #include <string.h>    29 #include <stdlib.h>    30 #include <unistd.h> /* sleep */    31     32 #include <fsclient/client.h>    33 #include <systypes/fcntl.h>    34     35     36     37 /* Use the writer to fill the pipe with data. */    38     39 static void write_pipe(file_t *writer, int number)    40 {    41   offset_t size = 600;    42   char buffer[size];    43   long err;    44     45   /* Make writers blocking to permit synchronisation. */    46     47   if ((err = client_set_blocking(writer, NOTIFY_SPACE_AVAILABLE)))    48   {    49     printf("Could not set pipe #%d as blocking: %s\n", number, l4sys_errtostr(err));    50     return;    51   }    52     53   for (int loop = 0; loop < 3; loop++)    54   {    55     for (int region = 0; region < 26; region++)    56     {    57       memset(buffer, (int) 'a' + region, size);    58     59       offset_t nwritten = client_write(writer, buffer, size);    60     61       printf("Written %ld/%ld in #%d of %d/%d to pipe #%d...\n", nwritten, size, region, loop, 2, number);    62     }    63     64     sleep(1);    65   }    66     67   /* Flush to make the final output available. */    68     69   client_close(writer);    70 }    71     72 /* Use the reader to obtain data from the pipe. */    73     74 static void read_pipes(file_t *reader1, file_t *reader2)    75 {    76   offset_t size = 600, totals[] = {0, 0};    77   unsigned int active = 2;    78   long err;    79   file_t *reader;    80     81   /* Use a local notifier to wait for pipe events. */    82     83   file_notifier_t *notifier = client_notifier_local();    84     85   /* Register the readers for notification. */    86     87   if ((err = client_subscribe(reader1, NOTIFY_CONTENT_AVAILABLE | NOTIFY_PEER_CLOSED, notifier)) ||    88       (err = client_subscribe(reader2, NOTIFY_CONTENT_AVAILABLE | NOTIFY_PEER_CLOSED, notifier)))    89   {    90     printf("Could not subscribe to notifications: %s\n", l4sys_errtostr(err));    91     return;    92   }    93     94   while (1)    95   {    96     char buffer[size];    97     offset_t nread;    98     99     /* Wait for notification of content. */   100    101     err = client_wait_files(&reader, notifier);   102    103     if (err)   104     {   105       printf("Error waiting for notifications: %s\n", l4sys_errtostr(err));   106       client_notifier_close(notifier);   107       return;   108     }   109    110     if ((reader != reader1) && (reader != reader2))   111     {   112       printf("Spurious notification received for %p versus %p, %p.\n", reader, reader1, reader2);   113       continue;   114     }   115    116     int p = reader == reader1 ? 0 : 1;   117    118     printf("Pipe #%d notified with conditions:%s%s\n", p + 1, reader->notifications & NOTIFY_PEER_CLOSED ? " closed" : "",   119                                                               reader->notifications & NOTIFY_CONTENT_AVAILABLE ? " content" : "");   120    121     nread = client_read(reader, buffer, size);   122    123     while (nread)   124     {   125       totals[p] += nread;   126    127       printf("Read %ld/%ld, total %ld, first %c, last %c, from pipe #%d...\n", nread, size, totals[p], *buffer, *(buffer + nread - 1), p + 1);   128 #if 0   129       for (offset_t i = 0; i < nread; i += 60)   130       {   131         fwrite(buffer + i, sizeof(char), nread - i > 60 ? 60 : nread - i, stdout);   132         fputs("\n", stdout);   133       }   134 #endif   135       nread = client_read(reader, buffer, size);   136     }   137    138     /* Without any more content, a peer closed event should terminate reading   139        from the pipe. */   140    141     if (reader->notifications & NOTIFY_PEER_CLOSED)   142     {   143       active--;   144       if (!active)   145         break;   146     }   147   }   148    149   client_close(reader1);   150   client_close(reader2);   151   client_notifier_close(notifier);   152    153   printf("Data shown.\n");   154 }   155    156 int main(void)   157 {   158   /* Obtain pipe endpoint references. Blocking will be set up manually. */   159    160   file_t *reader1, *reader2, *writer1, *writer2;   161   long err = client_pipe(&reader1, &writer1, O_NONBLOCK) ||   162              client_pipe(&reader2, &writer2, O_NONBLOCK);   163    164   if (err)   165   {   166     printf("Could not obtain pipes: %s\n", l4sys_errtostr(err));   167     return 1;   168   }   169    170   /* Schedule reader and writer threads. */   171    172   std::thread *activities[3];   173    174   activities[0] = new std::thread(read_pipes, reader1, reader2);   175   activities[1] = new std::thread(write_pipe, writer1, 1);   176   activities[2] = new std::thread(write_pipe, writer2, 2);   177    178   for (int i = 0; i < 3; i++)   179     activities[i]->join();   180 }   181    182 // vim: tabstop=2 expandtab shiftwidth=2