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