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 34 35 36 /* Use the writer to fill the pipe with data. */ 37 38 static void write_pipe(file_t *writer, int number) 39 { 40 offset_t size = 600; 41 char buffer[size]; 42 long err; 43 44 /* Make writers blocking to permit synchronisation. */ 45 46 if ((err = client_set_blocking(writer, NOTIFY_SPACE_AVAILABLE))) 47 { 48 printf("Could not set pipe #%d as blocking: %s\n", number, l4sys_errtostr(err)); 49 return; 50 } 51 52 for (int loop = 0; loop < 3; loop++) 53 { 54 for (int region = 0; region < 26; region++) 55 { 56 memset(buffer, (int) 'a' + region, size); 57 58 offset_t nwritten = client_write(writer, buffer, size); 59 60 printf("Written %ld/%ld in #%d of %d/%d to pipe #%d...\n", nwritten, size, region, loop, 2, number); 61 } 62 63 sleep(1); 64 } 65 66 /* Flush to make the final output available. */ 67 68 client_flush(writer); 69 70 client_close(writer); 71 } 72 73 /* Use the reader to obtain data from the pipe. */ 74 75 static void read_pipes(file_t *reader1, file_t *reader2) 76 { 77 offset_t size = 600, totals[] = {0, 0}; 78 unsigned int active = 2; 79 long err; 80 file_t *reader; 81 82 /* Register the readers for notification. */ 83 84 if ((err = client_subscribe(reader1, NOTIFY_CONTENT_AVAILABLE | NOTIFY_PEER_CLOSED)) || 85 (err = client_subscribe(reader2, NOTIFY_CONTENT_AVAILABLE | NOTIFY_PEER_CLOSED))) 86 { 87 printf("Could not subscribe to notifications: %s\n", l4sys_errtostr(err)); 88 return; 89 } 90 91 while (1) 92 { 93 char buffer[size]; 94 offset_t nread; 95 96 /* Wait for notification of content. */ 97 98 err = client_wait_files(&reader); 99 100 if (err) 101 { 102 printf("Error waiting for notifications: %s\n", l4sys_errtostr(err)); 103 return; 104 } 105 106 if ((reader != reader1) && (reader != reader2)) 107 { 108 printf("Spurious notification received for %p versus %p, %p.\n", reader, reader1, reader2); 109 continue; 110 } 111 112 int p = reader == reader1 ? 0 : 1; 113 114 printf("Pipe #%d notified with conditions:%s%s\n", p, reader->notifications & NOTIFY_PEER_CLOSED ? " closed" : "", 115 reader->notifications & NOTIFY_CONTENT_AVAILABLE ? " content" : ""); 116 117 nread = client_read(reader, buffer, size); 118 119 while (nread) 120 { 121 totals[p] += nread; 122 123 printf("Read %ld/%ld, total %ld, first %c, last %c, from pipe #%d...\n", nread, size, totals[p], *buffer, *(buffer + nread - 1), p + 1); 124 #if 0 125 for (offset_t i = 0; i < nread; i += 60) 126 { 127 fwrite(buffer + i, sizeof(char), nread - i > 60 ? 60 : nread - i, stdout); 128 fputs("\n", stdout); 129 } 130 #endif 131 nread = client_read(reader, buffer, size); 132 } 133 134 /* Without any more content, a peer closed event should terminate reading 135 from the pipe. */ 136 137 if (reader->notifications & NOTIFY_PEER_CLOSED) 138 { 139 active--; 140 if (!active) 141 break; 142 } 143 } 144 145 client_close(reader1); 146 client_close(reader2); 147 148 printf("Data shown.\n"); 149 } 150 151 int main(void) 152 { 153 /* Invoke the open method to receive the pipe endpoint references. */ 154 155 file_t *reader1, *reader2, *writer1, *writer2; 156 long err = client_pipe(&reader1, &writer1) || client_pipe(&reader2, &writer2); 157 158 if (err) 159 { 160 printf("Could not obtain pipes: %s\n", l4sys_errtostr(err)); 161 return 1; 162 } 163 164 /* Schedule reader and writer threads. */ 165 166 std::thread *activities[3]; 167 168 activities[0] = new std::thread(read_pipes, reader1, reader2); 169 activities[1] = new std::thread(write_pipe, writer1, 1); 170 activities[2] = new std::thread(write_pipe, writer2, 2); 171 172 for (int i = 0; i < 3; i++) 173 activities[i]->join(); 174 } 175 176 // vim: tabstop=2 expandtab shiftwidth=2