1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/conf/dstest_file.cfg Fri Jul 16 00:39:24 2021 +0200
1.3 @@ -0,0 +1,23 @@
1.4 +-- vim:set ft=lua:
1.5 +
1.6 +local L4 = require("L4");
1.7 +
1.8 +local l = L4.default_loader;
1.9 +
1.10 +local server = l:new_channel();
1.11 +
1.12 +l:startv({
1.13 + caps = {
1.14 + server = server:svr(),
1.15 + },
1.16 + log = { "server", "r" },
1.17 + },
1.18 + "rom/dstest_block_server", "10");
1.19 +
1.20 +l:startv({
1.21 + caps = {
1.22 + server = server,
1.23 + },
1.24 + log = { "client", "g" },
1.25 + },
1.26 + "rom/dstest_file_client", "rom/dstest_file.cfg");
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2.2 +++ b/conf/dstest_file.list Fri Jul 16 00:39:24 2021 +0200
2.3 @@ -0,0 +1,25 @@
2.4 +entry dstest_file
2.5 +roottask moe rom/dstest_file.cfg
2.6 +module dstest_file.cfg
2.7 +module l4re
2.8 +module ned
2.9 +module dstest_file_client
2.10 +module dstest_block_server
2.11 +module lib4re-c.so
2.12 +module lib4re-c-util.so
2.13 +module lib4re.so
2.14 +module lib4re-util.so
2.15 +module libc_be_l4refile.so
2.16 +module libc_be_l4re.so
2.17 +module libc_be_socket_noop.so
2.18 +module libc_support_misc.so
2.19 +module libdl.so
2.20 +module libipc.so
2.21 +module libl4sys-direct.so
2.22 +module libl4sys.so
2.23 +module libl4util.so
2.24 +module libld-l4.so
2.25 +module libpthread.so
2.26 +module libstdc++.so
2.27 +module libsupc++.so
2.28 +module libuc_c.so
3.1 --- a/libfsserver/include/fsserver/file_pager.h Fri Jul 16 00:38:55 2021 +0200
3.2 +++ b/libfsserver/include/fsserver/file_pager.h Fri Jul 16 00:39:24 2021 +0200
3.3 @@ -34,6 +34,14 @@
3.4 protected:
3.5 FilePaging *_paging;
3.6
3.7 + /* Notification endpoint for event subscription. */
3.8 +
3.9 + unsigned int _endpoint;
3.10 +
3.11 + /* Resize flag for notification. */
3.12 +
3.13 + bool _resized = false;
3.14 +
3.15 public:
3.16 fileid_t fileid;
3.17
3.18 @@ -64,6 +72,12 @@
3.19
3.20 virtual long mmap(offset_t position, offset_t length, offset_t *start_pos,
3.21 offset_t *end_pos, offset_t *size);
3.22 +
3.23 + /* Notification methods. */
3.24 +
3.25 + virtual long subscribe(l4_cap_idx_t notifier, notify_flags_t flags);
3.26 +
3.27 + virtual long unsubscribe(l4_cap_idx_t notifier);
3.28 };
3.29
3.30 // vim: tabstop=4 expandtab shiftwidth=4
4.1 --- a/libfsserver/include/fsserver/file_paging.h Fri Jul 16 00:38:55 2021 +0200
4.2 +++ b/libfsserver/include/fsserver/file_paging.h Fri Jul 16 00:39:24 2021 +0200
4.3 @@ -25,6 +25,7 @@
4.4 #include <mutex>
4.5
4.6 #include <fsserver/accessor.h>
4.7 +#include <fsserver/notification.h>
4.8 #include <fsserver/pager.h>
4.9 #include <fsserver/page_mapper.h>
4.10
4.11 @@ -39,7 +40,7 @@
4.12
4.13 /* A registry of mappers for accessors. */
4.14
4.15 -class FilePaging
4.16 +class FilePaging : public NotificationSupport
4.17 {
4.18 protected:
4.19 Pages *_pages;
4.20 @@ -55,9 +56,11 @@
4.21
4.22 /* Configurable methods. */
4.23
4.24 - virtual fileid_t get_fileid(const char *path) = 0;
4.25 + virtual map_flags_t get_flags(flags_t flags);
4.26
4.27 - virtual map_flags_t get_flags(flags_t flags);
4.28 + /* Configurable methods requiring implementation. */
4.29 +
4.30 + virtual fileid_t get_fileid(const char *path) = 0;
4.31
4.32 virtual Accessor *make_accessor(const char *path, fileid_t fileid) = 0;
4.33
4.34 @@ -72,8 +75,6 @@
4.35 public:
4.36 explicit FilePaging(Pages *pages);
4.37
4.38 - virtual ~FilePaging();
4.39 -
4.40 /* Methods for the pager. */
4.41
4.42 void detach_pager(fileid_t fileid, PageMapper *mapper);
5.1 --- a/libfsserver/lib/Makefile Fri Jul 16 00:38:55 2021 +0200
5.2 +++ b/libfsserver/lib/Makefile Fri Jul 16 00:39:24 2021 +0200
5.3 @@ -16,7 +16,7 @@
5.4 # Compound interfaces.
5.5
5.6 mapped_file_object_NAME = MappedFileObject
5.7 -mapped_file_object_INTERFACES = dataspace file flush mapped_file
5.8 +mapped_file_object_INTERFACES = dataspace file flush mapped_file notification
5.9
5.10 opener_context_object_NAME = OpenerContextObject
5.11 opener_context_object_INTERFACES = dataspace opener_context
6.1 --- a/libfsserver/lib/files/file_pager.cc Fri Jul 16 00:38:55 2021 +0200
6.2 +++ b/libfsserver/lib/files/file_pager.cc Fri Jul 16 00:39:24 2021 +0200
6.3 @@ -51,6 +51,10 @@
6.4 void FilePager::close()
6.5 {
6.6 _paging->detach_pager(fileid, _mapper);
6.7 +
6.8 + /* Notify other users of the file. */
6.9 +
6.10 + _paging->notify_others(_endpoint, NOTIFY_PEER_CLOSED);
6.11 }
6.12
6.13
6.14 @@ -59,12 +63,29 @@
6.15
6.16 long FilePager::flush(offset_t populated_size, offset_t *size)
6.17 {
6.18 - return Pager::flush(populated_size, size);
6.19 + long err = Pager::flush(populated_size, size);
6.20 +
6.21 + if (_resized)
6.22 + {
6.23 + _paging->notify_others(_endpoint, NOTIFY_CONTENT_AVAILABLE);
6.24 + _resized = false;
6.25 + }
6.26 +
6.27 + return err;
6.28 }
6.29
6.30 long FilePager::resize(offset_t *size)
6.31 {
6.32 - return Pager::resize(size);
6.33 + offset_t old_size = get_data_size();
6.34 + long err = Pager::resize(size);
6.35 +
6.36 + /* If the size has changed, notify other users, but only after data has been
6.37 + flushed. */
6.38 +
6.39 + if (old_size < get_data_size())
6.40 + _resized = true;
6.41 +
6.42 + return err;
6.43 }
6.44
6.45 long FilePager::mmap(offset_t position, offset_t length, offset_t *start_pos,
6.46 @@ -84,4 +105,23 @@
6.47 return Pager::map(offset, hot_spot, flags, region);
6.48 }
6.49
6.50 +
6.51 +
6.52 +/* Subscribe to notifications. */
6.53 +
6.54 +long FilePager::subscribe(l4_cap_idx_t notifier, notify_flags_t flags)
6.55 +{
6.56 + /* Readers can subscribe to new data (at end), and pipe closed events.
6.57 + Writers can subscribe to new space and pipe closed events. */
6.58 +
6.59 + _endpoint = _paging->subscribe(notifier, flags);
6.60 + return L4_EOK;
6.61 +}
6.62 +
6.63 +long FilePager::unsubscribe(l4_cap_idx_t notifier)
6.64 +{
6.65 + _paging->unsubscribe(_endpoint, notifier);
6.66 + return L4_EOK;
6.67 +}
6.68 +
6.69 // vim: tabstop=4 expandtab shiftwidth=4
7.1 --- a/libfsserver/lib/files/file_paging.cc Fri Jul 16 00:38:55 2021 +0200
7.2 +++ b/libfsserver/lib/files/file_paging.cc Fri Jul 16 00:39:24 2021 +0200
7.3 @@ -27,11 +27,7 @@
7.4
7.5
7.6 FilePaging::FilePaging(Pages *pages)
7.7 -: _pages(pages)
7.8 -{
7.9 -}
7.10 -
7.11 -FilePaging::~FilePaging()
7.12 +: NotificationSupport(), _pages(pages)
7.13 {
7.14 }
7.15
8.1 --- a/tests/Makefile Fri Jul 16 00:38:55 2021 +0200
8.2 +++ b/tests/Makefile Fri Jul 16 00:39:24 2021 +0200
8.3 @@ -4,6 +4,7 @@
8.4 TARGET = \
8.5 dstest_block_client dstest_block_client_simple \
8.6 dstest_ext2fs_client \
8.7 + dstest_file_client \
8.8 dstest_host_client \
8.9 dstest_pipe_client \
8.10 dstest_test_client \
8.11 @@ -16,6 +17,8 @@
8.12
8.13 SRC_CC_dstest_ext2fs_client = dstest_ext2fs_client.cc
8.14
8.15 +SRC_CC_dstest_file_client = dstest_file_client.cc
8.16 +
8.17 SRC_CC_dstest_host_client = dstest_host_client.cc
8.18
8.19 SRC_CC_dstest_pipe_client = dstest_pipe_client.cc
9.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
9.2 +++ b/tests/dstest_file_client.cc Fri Jul 16 00:39:24 2021 +0200
9.3 @@ -0,0 +1,168 @@
9.4 +/*
9.5 + * Test file operations.
9.6 + *
9.7 + * Copyright (C) 2020, 2021 Paul Boddie <paul@boddie.org.uk>
9.8 + *
9.9 + * This program is free software; you can redistribute it and/or
9.10 + * modify it under the terms of the GNU General Public License as
9.11 + * published by the Free Software Foundation; either version 2 of
9.12 + * the License, or (at your option) any later version.
9.13 + *
9.14 + * This program is distributed in the hope that it will be useful,
9.15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
9.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9.17 + * GNU General Public License for more details.
9.18 + *
9.19 + * You should have received a copy of the GNU General Public License
9.20 + * along with this program; if not, write to the Free Software
9.21 + * Foundation, Inc., 51 Franklin Street, Fifth Floor,
9.22 + * Boston, MA 02110-1301, USA
9.23 + */
9.24 +
9.25 +#include <l4/re/env.h>
9.26 +#include <l4/sys/err.h>
9.27 +
9.28 +#include <thread>
9.29 +
9.30 +#include <stdio.h>
9.31 +#include <string.h>
9.32 +#include <stdlib.h>
9.33 +
9.34 +#include <fsclient/client.h>
9.35 +#include <systypes/fcntl.h>
9.36 +
9.37 +
9.38 +
9.39 +/* Write data to the file. */
9.40 +
9.41 +static void write_data(file_t *file, int region)
9.42 +{
9.43 + offset_t size = 600;
9.44 + char buffer[size];
9.45 +
9.46 + memset(buffer, (int) 'a' + region, size);
9.47 +
9.48 + offset_t nwritten = client_write(file, buffer, size);
9.49 +
9.50 + printf("Written %ld/%ld in #%d to file with first %c, last %c...\n", nwritten, size, region, *buffer, *(buffer + nwritten - 1));
9.51 +
9.52 + /* Flush to make the output available. */
9.53 +
9.54 + client_flush(file);
9.55 +}
9.56 +
9.57 +/* Read and write data to the file. */
9.58 +
9.59 +static void read_and_write(file_t *file, bool creator)
9.60 +{
9.61 + offset_t size = 600, total = 0;
9.62 + long err;
9.63 + int region = 0;
9.64 +
9.65 + /* Register for notifications. */
9.66 +
9.67 + if ((err = client_subscribe(file, NOTIFY_CONTENT_AVAILABLE | NOTIFY_PEER_CLOSED)))
9.68 + {
9.69 + printf("Could not subscribe to notifications: %s\n", l4sys_errtostr(err));
9.70 + return;
9.71 + }
9.72 +
9.73 + /* Seek to the end of the file, if this is not actually a new file. */
9.74 +
9.75 + client_seek(file, 0, SEEK_END);
9.76 +
9.77 + printf("File %s at position %ld...\n", creator ? "creator" : "follower", client_tell(file));
9.78 +
9.79 + /* Write initial data as the file's creator. */
9.80 +
9.81 + if (creator)
9.82 + write_data(file, region++);
9.83 +
9.84 + while (region < 26)
9.85 + {
9.86 + char buffer[size];
9.87 + offset_t nread;
9.88 +
9.89 + /* Wait for notification of content. */
9.90 +
9.91 + err = client_wait_file(file);
9.92 +
9.93 + if (err)
9.94 + {
9.95 + printf("Error waiting for notifications: %s\n", l4sys_errtostr(err));
9.96 + return;
9.97 + }
9.98 +
9.99 + printf("File %s notified with conditions:%s%s\n", creator ? "creator" : "follower",
9.100 + file->notifications & NOTIFY_PEER_CLOSED ? " closed" : "",
9.101 + file->notifications & NOTIFY_CONTENT_AVAILABLE ? " content" : "");
9.102 +
9.103 + /* Attempt to read. */
9.104 +
9.105 + nread = client_read(file, buffer, size);
9.106 +
9.107 + while (nread)
9.108 + {
9.109 + total += nread;
9.110 +
9.111 + printf("Read as %s %ld/%ld, total %ld, first %c, last %c, from file...\n", creator ? "creator" : "follower",
9.112 + nread, size, total, *buffer, *(buffer + nread - 1));
9.113 +
9.114 + if (!(*(buffer + nread - 1)))
9.115 + printf("Warning: length before zero region is %ld\n", strlen(buffer));
9.116 +
9.117 +#if 0
9.118 + for (offset_t i = 0; i < nread; i += 60)
9.119 + {
9.120 + fwrite(buffer + i, sizeof(char), nread - i > 60 ? 60 : nread - i, stdout);
9.121 + fputs("\n", stdout);
9.122 + }
9.123 +#endif
9.124 + nread = client_read(file, buffer, size);
9.125 + }
9.126 +
9.127 + /* Without any more content, a peer closed event should terminate reading
9.128 + from the pipe. */
9.129 +
9.130 + if (file->notifications & NOTIFY_PEER_CLOSED)
9.131 + break;
9.132 +
9.133 + write_data(file, region++);
9.134 + }
9.135 +
9.136 + printf("Data shown.\n");
9.137 +}
9.138 +
9.139 +int main(int argc, char *argv[])
9.140 +{
9.141 + if (argc < 2)
9.142 + {
9.143 + printf("Need a filename.\n");
9.144 + return 1;
9.145 + }
9.146 +
9.147 + char *filename = argv[1];
9.148 +
9.149 + /* Invoke the open function to receive each file reference. */
9.150 +
9.151 + file_t *file1 = client_open(filename, O_RDWR); // | O_CREAT
9.152 + file_t *file2 = client_open(filename, O_RDWR);
9.153 +
9.154 + if ((file1 == NULL) || (file2 == NULL))
9.155 + {
9.156 + printf("Could not obtain files.\n");
9.157 + return 1;
9.158 + }
9.159 +
9.160 + /* Schedule threads. */
9.161 +
9.162 + std::thread *activities[2];
9.163 +
9.164 + activities[0] = new std::thread(read_and_write, file1, true);
9.165 + activities[1] = new std::thread(read_and_write, file2, false);
9.166 +
9.167 + for (int i = 0; i < 2; i++)
9.168 + activities[i]->join();
9.169 +}
9.170 +
9.171 +// vim: tabstop=2 expandtab shiftwidth=2