1 /* 2 * Test file 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 31 #include <fsclient/client.h> 32 #include <systypes/fcntl.h> 33 34 35 36 /* Write data to the file. */ 37 38 static void write_data(file_t *file, int region) 39 { 40 offset_t size = 600; 41 char buffer[size]; 42 43 memset(buffer, (int) 'a' + region, size); 44 45 offset_t nwritten = client_write(file, buffer, size); 46 47 printf("Written %ld/%ld in #%d to file with first %c, last %c...\n", nwritten, size, region, *buffer, *(buffer + nwritten - 1)); 48 49 /* Flush to make the output available. */ 50 51 client_flush(file); 52 } 53 54 /* Read and write data to the file. */ 55 56 static void read_and_write(file_t *file, bool creator) 57 { 58 offset_t size = 600, total = 0; 59 long err; 60 int region = 0; 61 62 /* Register for notifications. */ 63 64 if ((err = client_subscribe(file, NOTIFY_CONTENT_AVAILABLE | NOTIFY_PEER_CLOSED))) 65 { 66 printf("Could not subscribe to notifications: %s\n", l4sys_errtostr(err)); 67 return; 68 } 69 70 /* Seek to the end of the file, if this is not actually a new file. */ 71 72 client_seek(file, 0, SEEK_END); 73 74 printf("File %s at position %ld...\n", creator ? "creator" : "follower", client_tell(file)); 75 76 /* Write initial data as the file's creator. */ 77 78 if (creator) 79 write_data(file, region++); 80 81 while (region < 26) 82 { 83 char buffer[size]; 84 offset_t nread; 85 86 /* Wait for notification of content. */ 87 88 err = client_wait_file(file); 89 90 if (err) 91 { 92 printf("Error waiting for notifications: %s\n", l4sys_errtostr(err)); 93 return; 94 } 95 96 printf("File %s notified with conditions:%s%s\n", creator ? "creator" : "follower", 97 file->notifications & NOTIFY_PEER_CLOSED ? " closed" : "", 98 file->notifications & NOTIFY_CONTENT_AVAILABLE ? " content" : ""); 99 100 /* Attempt to read. */ 101 102 nread = client_read(file, buffer, size); 103 104 while (nread) 105 { 106 total += nread; 107 108 printf("Read as %s %ld/%ld, total %ld, first %c, last %c, from file...\n", creator ? "creator" : "follower", 109 nread, size, total, *buffer, *(buffer + nread - 1)); 110 111 if (!(*(buffer + nread - 1))) 112 printf("Warning: length before zero region is %ld\n", strlen(buffer)); 113 114 #if 0 115 for (offset_t i = 0; i < nread; i += 60) 116 { 117 fwrite(buffer + i, sizeof(char), nread - i > 60 ? 60 : nread - i, stdout); 118 fputs("\n", stdout); 119 } 120 #endif 121 nread = client_read(file, buffer, size); 122 } 123 124 /* Without any more content, a peer closed event should terminate reading 125 from the pipe. */ 126 127 if (file->notifications & NOTIFY_PEER_CLOSED) 128 break; 129 130 write_data(file, region++); 131 } 132 133 printf("Data shown.\n"); 134 } 135 136 int main(int argc, char *argv[]) 137 { 138 if (argc < 2) 139 { 140 printf("Need a filename.\n"); 141 return 1; 142 } 143 144 char *filename = argv[1]; 145 146 /* Invoke the open function to receive each file reference. */ 147 148 file_t *file1 = client_open(filename, O_RDWR | O_CREAT); 149 file_t *file2 = client_open(filename, O_RDWR); 150 151 if ((file1 == NULL) || (file2 == NULL)) 152 { 153 printf("Could not obtain files.\n"); 154 return 1; 155 } 156 157 /* Schedule threads. */ 158 159 std::thread *activities[2]; 160 161 activities[0] = new std::thread(read_and_write, file1, true); 162 activities[1] = new std::thread(read_and_write, file2, false); 163 164 for (int i = 0; i < 2; i++) 165 activities[i]->join(); 166 } 167 168 // vim: tabstop=2 expandtab shiftwidth=2