1.1 --- a/libfsclient/include/fsclient/client.h Sat May 15 23:38:39 2021 +0200
1.2 +++ b/libfsclient/include/fsclient/client.h Tue May 18 00:55:20 2021 +0200
1.3 @@ -27,7 +27,7 @@
1.4
1.5 EXTERN_C_BEGIN
1.6
1.7 -/* File operations. */
1.8 +/* Opening and closing operations. */
1.9
1.10 void client_close(file_t *file);
1.11 file_t *client_open(const char *name, flags_t flags);
1.12 @@ -54,6 +54,13 @@
1.13 offset_t client_seek(file_t *file, offset_t offset, int whence);
1.14 long client_tell(file_t *file);
1.15
1.16 +/* Notification operations. */
1.17 +
1.18 +long client_set_blocking(file_t *file, int can_block);
1.19 +long client_subscribe(file_t *file, flags_t flags);
1.20 +long client_unsubscribe(file_t *file);
1.21 +long client_wait(file_t *file);
1.22 +
1.23 EXTERN_C_END
1.24
1.25 // vim: tabstop=2 expandtab shiftwidth=2
2.1 --- a/libfsclient/include/fsclient/file.h Sat May 15 23:38:39 2021 +0200
2.2 +++ b/libfsclient/include/fsclient/file.h Tue May 18 00:55:20 2021 +0200
2.3 @@ -37,6 +37,10 @@
2.4
2.5 l4_cap_idx_t ref;
2.6
2.7 + /* Notification IRQ reference. */
2.8 +
2.9 + l4_cap_idx_t irq;
2.10 +
2.11 /* Mapped memory accessing a file region. */
2.12
2.13 char *memory;
2.14 @@ -59,6 +63,10 @@
2.15
2.16 int has_size;
2.17
2.18 + /* Blocking accesses. */
2.19 +
2.20 + int can_block;
2.21 +
2.22 } file_t;
2.23
2.24
2.25 @@ -103,6 +111,12 @@
2.26 void file_data_read(file_t *file, char *buf, offset_t to_transfer);
2.27 void file_data_write(file_t *file, char *buf, offset_t to_transfer);
2.28
2.29 +/* Notification functions. */
2.30 +
2.31 +long file_notify_subscribe(file_t *file, flags_t flags);
2.32 +long file_notify_unsubscribe(file_t *file);
2.33 +long file_notify_wait(file_t *file);
2.34 +
2.35
2.36
2.37 /* Pipe operations. */
2.38 @@ -115,6 +129,8 @@
2.39 long pipe_next(file_t *pipe);
2.40 long pipe_written(file_t *pipe, offset_t size);
2.41
2.42 +
2.43 +
2.44 EXTERN_C_END
2.45
2.46 // vim: tabstop=2 expandtab shiftwidth=2
3.1 --- a/libfsclient/lib/src/Makefile Sat May 15 23:38:39 2021 +0200
3.2 +++ b/libfsclient/lib/src/Makefile Tue May 18 00:55:20 2021 +0200
3.3 @@ -15,7 +15,7 @@
3.4
3.5 # Individual interfaces.
3.6
3.7 -CLIENT_INTERFACES_CC = dataspace file mapped_file opener opener_context pipe pipe_opener
3.8 +CLIENT_INTERFACES_CC = dataspace file flush mapped_file notification opener opener_context pipe pipe_opener
3.9
3.10 # Generated and plain source files.
3.11
4.1 --- a/libfsclient/lib/src/client.cc Sat May 15 23:38:39 2021 +0200
4.2 +++ b/libfsclient/lib/src/client.cc Tue May 18 00:55:20 2021 +0200
4.3 @@ -34,6 +34,114 @@
4.4
4.5
4.6
4.7 +/* Access the given position and synchronise state with the file object. */
4.8 +
4.9 +static long _access(file_t *file, offset_t position)
4.10 +{
4.11 + long err;
4.12 +
4.13 + if (file->can_mmap)
4.14 + {
4.15 + /* Where the position is outside the current region, re-map. */
4.16 +
4.17 + if ((position < file->start_pos) || (position >= file->end_pos))
4.18 + {
4.19 + if (file_mmap(file, position, file_span(file)))
4.20 + return -L4_EIO;
4.21 + }
4.22 +
4.23 + /* Otherwise, flush any written data in the current region and update the
4.24 + file size details. */
4.25 +
4.26 + else
4.27 + {
4.28 + err = client_flush(file);
4.29 + if (err)
4.30 + return err;
4.31 + }
4.32 + }
4.33 + else
4.34 + {
4.35 + /* Strict conditions for region navigation in pipes. */
4.36 +
4.37 + if ((position < file->start_pos) || (position > file->end_pos))
4.38 + {
4.39 + return -L4_EIO;
4.40 + }
4.41 +
4.42 + /* The next region is only available at the end of the mapped memory. */
4.43 +
4.44 + else if (position == file->end_pos)
4.45 + {
4.46 + err = client_next_region(file);
4.47 + if (err)
4.48 + return err;
4.49 +
4.50 + file->data_current = 0;
4.51 + return L4_EOK;
4.52 + }
4.53 +
4.54 + /* Within the current pipe region, synchronise with the pipe object. */
4.55 +
4.56 + else
4.57 + {
4.58 + err = client_current_region(file);
4.59 + if (err)
4.60 + return err;
4.61 + }
4.62 + }
4.63 +
4.64 + /* Update the current data offset. */
4.65 +
4.66 + file->data_current = position - file->start_pos;
4.67 +
4.68 + return L4_EOK;
4.69 +}
4.70 +
4.71 +
4.72 +
4.73 +/* Return whether an access could occur, blocking if necessary. */
4.74 +
4.75 +static int _access_blocking(file_t *file, offset_t position)
4.76 +{
4.77 + long err;
4.78 +
4.79 + while ((err = _access(file, position)))
4.80 + {
4.81 + /* Exit if blocking is not configured or suitable. */
4.82 +
4.83 + if ((err != -L4_EBUSY) || !file->can_block)
4.84 + return 0;
4.85 +
4.86 + /* Handle an inability to access by blocking, exiting if waiting failed. */
4.87 +
4.88 + if (client_wait(file))
4.89 + return 0;
4.90 + }
4.91 +
4.92 + return 1;
4.93 +}
4.94 +
4.95 +
4.96 +
4.97 +/* Ensure that memory is mapped for accessing the given file, using the
4.98 + indicated count as a region size hint. */
4.99 +
4.100 +static void *_map_memory(file_t *file, offset_t count)
4.101 +{
4.102 + if (file->memory == NULL)
4.103 + {
4.104 + if (file->can_mmap)
4.105 + return client_mmap(file, client_tell(file), count);
4.106 + else if (pipe_current(file))
4.107 + return NULL;
4.108 + }
4.109 +
4.110 + return file->memory;
4.111 +}
4.112 +
4.113 +
4.114 +
4.115 /* Close a filesystem object. */
4.116
4.117 void client_close(file_t *file)
4.118 @@ -108,72 +216,6 @@
4.119
4.120
4.121
4.122 -/* Access the given position and synchronise state with the file object. */
4.123 -
4.124 -static long _access(file_t *file, offset_t position)
4.125 -{
4.126 - long err;
4.127 -
4.128 - if (file->can_mmap)
4.129 - {
4.130 - /* Where the position is outside the current region, re-map. */
4.131 -
4.132 - if ((position < file->start_pos) || (position >= file->end_pos))
4.133 - {
4.134 - if (file_mmap(file, position, file_span(file)))
4.135 - return -L4_EIO;
4.136 - }
4.137 -
4.138 - /* Otherwise, flush any written data in the current region and update the
4.139 - file size details. */
4.140 -
4.141 - else
4.142 - {
4.143 - err = client_flush(file);
4.144 - if (err)
4.145 - return err;
4.146 - }
4.147 - }
4.148 - else
4.149 - {
4.150 - /* Strict conditions for region navigation in pipes. */
4.151 -
4.152 - if ((position < file->start_pos) || (position > file->end_pos))
4.153 - {
4.154 - return -L4_EIO;
4.155 - }
4.156 -
4.157 - /* The next region is only available at the end of the mapped memory. */
4.158 -
4.159 - else if (position == file->end_pos)
4.160 - {
4.161 - err = client_next_region(file);
4.162 - if (err)
4.163 - return err;
4.164 - }
4.165 -
4.166 - /* Within the current pipe region, synchronise with the pipe object. */
4.167 -
4.168 - else
4.169 - {
4.170 - err = client_current_region(file);
4.171 - if (err)
4.172 - return err;
4.173 - }
4.174 - }
4.175 -
4.176 - /* Update the current data offset. */
4.177 -
4.178 - if (file->has_size)
4.179 - file->data_current = position - file->start_pos;
4.180 - else
4.181 - file->data_current = 0;
4.182 -
4.183 - return L4_EOK;
4.184 -}
4.185 -
4.186 -
4.187 -
4.188 /* Flush data explicitly to the filesystem object. */
4.189
4.190 long client_flush(file_t *file)
4.191 @@ -224,24 +266,6 @@
4.192
4.193
4.194
4.195 -/* Ensure that memory is mapped for accessing the given file, using the
4.196 - indicated count as a region size hint. */
4.197 -
4.198 -static void *_map_memory(file_t *file, offset_t count)
4.199 -{
4.200 - if (file->memory == NULL)
4.201 - {
4.202 - if (file->can_mmap)
4.203 - return client_mmap(file, client_tell(file), count);
4.204 - else if (pipe_current(file))
4.205 - return NULL;
4.206 - }
4.207 -
4.208 - return file->memory;
4.209 -}
4.210 -
4.211 -
4.212 -
4.213 /* Read from the filesystem object into the buffer provided. */
4.214
4.215 offset_t client_read(file_t *file, void *buf, offset_t count)
4.216 @@ -268,7 +292,7 @@
4.217 /* Flush any unwritten data, preparing to read from the file position at
4.218 the end of the data, and returning if no new data is available. */
4.219
4.220 - if (_access(file, file_data_end_position(file)))
4.221 + if (!_access_blocking(file, file_data_end_position(file)))
4.222 break;
4.223
4.224 available = file_data_available(file);
4.225 @@ -323,7 +347,7 @@
4.226
4.227 default:
4.228 /* NOTE: Set errno to EINVAL. */
4.229 - return -1;
4.230 + return current;
4.231 }
4.232
4.233 /* Retain the current position if unchanged. */
4.234 @@ -365,12 +389,53 @@
4.235
4.236 /* Handle unwritten data and reset the buffer for reading. */
4.237
4.238 - _access(file, position);
4.239 + if (_access(file, position))
4.240 + return current;
4.241 +
4.242 return position;
4.243 }
4.244
4.245
4.246
4.247 +/* Set or unset blocking access for a file. */
4.248 +
4.249 +long client_set_blocking(file_t *file, int can_block)
4.250 +{
4.251 + long err;
4.252 +
4.253 + if (file->can_block == can_block)
4.254 + return L4_EOK;
4.255 +
4.256 + // NOTE: Set appropriate flags.
4.257 +
4.258 + if (can_block)
4.259 + err = client_subscribe(file, 0);
4.260 + else
4.261 + err = client_unsubscribe(file);
4.262 +
4.263 + if (err)
4.264 + return err;
4.265 +
4.266 + file->can_block = can_block;
4.267 + return L4_EOK;
4.268 +}
4.269 +
4.270 +
4.271 +
4.272 +/* Subscribe from events concerning a file. */
4.273 +
4.274 +long client_subscribe(file_t *file, flags_t flags)
4.275 +{
4.276 + if (file == NULL)
4.277 + return -L4_EINVAL;
4.278 +
4.279 + return file_notify_subscribe(file, flags);
4.280 +}
4.281 +
4.282 +
4.283 +
4.284 +/* Return the current position in the file. */
4.285 +
4.286 long client_tell(file_t *file)
4.287 {
4.288 if (file == NULL)
4.289 @@ -381,6 +446,30 @@
4.290
4.291
4.292
4.293 +/* Unsubscribe from events concerning a file. */
4.294 +
4.295 +long client_unsubscribe(file_t *file)
4.296 +{
4.297 + if (file == NULL)
4.298 + return -L4_EINVAL;
4.299 +
4.300 + return file_notify_unsubscribe(file);
4.301 +}
4.302 +
4.303 +
4.304 +
4.305 +/* Register for events concerning a file. */
4.306 +
4.307 +long client_wait(file_t *file)
4.308 +{
4.309 + if (file == NULL)
4.310 + return -L4_EINVAL;
4.311 +
4.312 + return file_notify_wait(file);
4.313 +}
4.314 +
4.315 +
4.316 +
4.317 /* Write to the filesystem object from the buffer provided. */
4.318
4.319 offset_t client_write(file_t *file, const void *buf, offset_t count)
4.320 @@ -424,7 +513,7 @@
4.321 /* Flush any unwritten data and continue writing from the current data
4.322 position. */
4.323
4.324 - if (_access(file, file_data_current_position(file)))
4.325 + if (!_access_blocking(file, file_data_current_position(file)))
4.326 break;
4.327
4.328 space = file_data_space(file);
5.1 --- a/libfsclient/lib/src/file.cc Sat May 15 23:38:39 2021 +0200
5.2 +++ b/libfsclient/lib/src/file.cc Tue May 18 00:55:20 2021 +0200
5.3 @@ -21,11 +21,19 @@
5.4
5.5 #include <ipc/cap_alloc.h>
5.6 #include <ipc/mem_ipc.h>
5.7 +#include <ipc/irq.h>
5.8 +
5.9 +#include <l4/sys/irq.h>
5.10 +
5.11 +#include <pthread.h>
5.12 +#include <pthread-l4.h>
5.13
5.14 #include <string.h>
5.15
5.16 #include "dataspace_client.h"
5.17 #include "file_client.h"
5.18 +#include "flush_client.h"
5.19 +#include "notification_client.h"
5.20 #include "opener_client.h"
5.21 #include "opener_context_client.h"
5.22 #include "pipe_client.h"
5.23 @@ -65,12 +73,14 @@
5.24 {
5.25 file->memory = NULL;
5.26 file->ref = L4_INVALID_CAP;
5.27 + file->irq = L4_INVALID_CAP;
5.28 file->start_pos = 0;
5.29 file->end_pos = 0;
5.30 file->data_end = 0;
5.31 file->data_current = 0;
5.32 file->can_mmap = 1;
5.33 file->has_size = 1;
5.34 + file->can_block = 0;
5.35 }
5.36
5.37
5.38 @@ -82,6 +92,9 @@
5.39 if (l4_is_valid_cap(file->ref))
5.40 ipc_cap_free_um(file->ref);
5.41
5.42 + if (l4_is_valid_cap(file->irq))
5.43 + ipc_cap_free_um(file->irq);
5.44 +
5.45 if (file->memory != NULL)
5.46 ipc_detach_dataspace(file->memory);
5.47
5.48 @@ -163,7 +176,7 @@
5.49
5.50 long file_flush(file_t *file)
5.51 {
5.52 - client_File _file(file->ref);
5.53 + client_Flush _file(file->ref);
5.54 long err = _file.flush(file->data_current, &file->size);
5.55
5.56 if (err)
5.57 @@ -361,6 +374,41 @@
5.58
5.59
5.60
5.61 +/* Subscribe to notification events on a file. */
5.62 +
5.63 +long file_notify_subscribe(file_t *file, flags_t flags)
5.64 +{
5.65 + client_Notification notify(file->ref);
5.66 +
5.67 + return notify.subscribe(flags, &file->irq);
5.68 +}
5.69 +
5.70 +/* Unsubscribe from notification events on a file. */
5.71 +
5.72 +long file_notify_unsubscribe(file_t *file)
5.73 +{
5.74 + client_Notification notify(file->ref);
5.75 +
5.76 + return notify.unsubscribe();
5.77 +}
5.78 +
5.79 +/* Wait for notification events on a file. */
5.80 +
5.81 +long file_notify_wait(file_t *file)
5.82 +{
5.83 + long err = ipc_bind_irq(file->irq, (l4_umword_t) &file->irq, pthread_l4_cap(pthread_self()));
5.84 +
5.85 + if (err)
5.86 + return err;
5.87 +
5.88 + l4_msgtag_t tag = l4_irq_receive(file->irq, L4_IPC_NEVER);
5.89 +
5.90 + l4_irq_detach(file->irq);
5.91 + return l4_error(tag);
5.92 +}
5.93 +
5.94 +
5.95 +
5.96 /* Open two pipe endpoints using the given pipe server. */
5.97
5.98 long pipe_open(offset_t size, file_t *reader, file_t *writer, l4_cap_idx_t server)
5.99 @@ -401,19 +449,20 @@
5.100 {
5.101 client_Pipe _pipe(pipe->ref);
5.102 long err = _pipe.current_region(&pipe->data_end, &pipe->size);
5.103 - char *memory = pipe->memory;
5.104
5.105 if (err)
5.106 return err;
5.107
5.108 pipe->end_pos = pipe->size;
5.109
5.110 - err = ipc_attach_dataspace(pipe->ref, file_span(pipe), (void **) &pipe->memory);
5.111 - if (err)
5.112 - return err;
5.113 + /* Attach memory if necessary. */
5.114
5.115 - if (memory != NULL)
5.116 - ipc_detach_dataspace(memory);
5.117 + if (pipe->memory == NULL)
5.118 + {
5.119 + err = ipc_attach_dataspace(pipe->ref, file_span(pipe), (void **) &pipe->memory);
5.120 + if (err)
5.121 + return err;
5.122 + }
5.123
5.124 return L4_EOK;
5.125 }
6.1 --- a/libfsserver/include/fsserver/pipe_pager.h Sat May 15 23:38:39 2021 +0200
6.2 +++ b/libfsserver/include/fsserver/pipe_pager.h Tue May 18 00:55:20 2021 +0200
6.3 @@ -64,9 +64,21 @@
6.4
6.5 /* Pipe methods. */
6.6
6.7 + virtual long closed(int *closed);
6.8 +
6.9 virtual long current_region(offset_t *populated_size, offset_t *size);
6.10
6.11 virtual long next_region(offset_t *populated_size, offset_t *size);
6.12 +
6.13 + /* Flushing/synchronisation. */
6.14 +
6.15 + virtual long flush(offset_t populated_size, offset_t *size);
6.16 +
6.17 + /* Notification methods. */
6.18 +
6.19 + virtual long subscribe(flags_t flags, l4_cap_idx_t *irq);
6.20 +
6.21 + virtual long unsubscribe();
6.22 };
6.23
6.24 // vim: tabstop=4 expandtab shiftwidth=4
7.1 --- a/libfsserver/include/fsserver/pipe_paging.h Sat May 15 23:38:39 2021 +0200
7.2 +++ b/libfsserver/include/fsserver/pipe_paging.h Tue May 18 00:55:20 2021 +0200
7.3 @@ -54,6 +54,10 @@
7.4
7.5 unsigned int _endpoints = 2;
7.6
7.7 + /* Notification IRQs. */
7.8 +
7.9 + l4_cap_idx_t _irqs[2];
7.10 +
7.11 public:
7.12 explicit PipePaging(Memory *memory, offset_t size);
7.13
7.14 @@ -62,6 +66,14 @@
7.15 virtual offset_t region_size()
7.16 { return _size; }
7.17
7.18 + /* Notification support. */
7.19 +
7.20 + virtual void notify(bool writing);
7.21 +
7.22 + virtual l4_cap_idx_t subscribe(bool writing);
7.23 +
7.24 + virtual void unsubscribe(bool writing);
7.25 +
7.26 /* Region management. */
7.27
7.28 virtual PageMapper *add_region();
8.1 --- a/libfsserver/lib/Makefile Sat May 15 23:38:39 2021 +0200
8.2 +++ b/libfsserver/lib/Makefile Tue May 18 00:55:20 2021 +0200
8.3 @@ -16,13 +16,13 @@
8.4 # Compound interfaces.
8.5
8.6 mapped_file_object_NAME = MappedFileObject
8.7 -mapped_file_object_INTERFACES = dataspace file mapped_file
8.8 +mapped_file_object_INTERFACES = dataspace file flush mapped_file
8.9
8.10 opener_context_object_NAME = OpenerContextObject
8.11 opener_context_object_INTERFACES = dataspace opener_context
8.12
8.13 pipe_object_NAME = PipeObject
8.14 -pipe_object_INTERFACES = dataspace pipe
8.15 +pipe_object_INTERFACES = dataspace flush notification pipe
8.16
8.17 COMP_INTERFACES_CC = mapped_file_object opener_context_object pipe_object
8.18
9.1 --- a/libfsserver/lib/pipes/pipe_pager.cc Sat May 15 23:38:39 2021 +0200
9.2 +++ b/libfsserver/lib/pipes/pipe_pager.cc Tue May 18 00:55:20 2021 +0200
9.3 @@ -55,6 +55,10 @@
9.4 void PipePager::close()
9.5 {
9.6 _paging->detach();
9.7 +
9.8 + /* Notify the other endpoint. */
9.9 +
9.10 + _paging->notify(_writing);
9.11 }
9.12
9.13 /* Support paging. */
9.14 @@ -66,6 +70,14 @@
9.15
9.16
9.17
9.18 +/* Return whether the pipe is closed or partly closed. */
9.19 +
9.20 +long PipePager::closed(int *closed)
9.21 +{
9.22 + *closed = _paging->closed();
9.23 + return L4_EOK;
9.24 +}
9.25 +
9.26 /* Return details of the current region. */
9.27
9.28 long PipePager::current_region(offset_t *populated_size, offset_t *size)
9.29 @@ -131,4 +143,37 @@
9.30 return -L4_EBUSY;
9.31 }
9.32
9.33 +
9.34 +
9.35 +/* Update the populated size of a pipe region and notify the other endpoint. */
9.36 +
9.37 +long PipePager::flush(offset_t populated_size, offset_t *size)
9.38 +{
9.39 + if (_mapper != NULL)
9.40 + _mapper->set_data_size(populated_size);
9.41 +
9.42 + *size = _size;
9.43 +
9.44 + _paging->notify(_writing);
9.45 + return L4_EOK;
9.46 +}
9.47 +
9.48 +
9.49 +
9.50 +/* Subscribe to notifications. */
9.51 +
9.52 +long PipePager::subscribe(flags_t flags, l4_cap_idx_t *irq)
9.53 +{
9.54 + // NOTE: Need to interpret flags.
9.55 +
9.56 + *irq = _paging->subscribe(_writing);
9.57 + return L4_EOK;
9.58 +}
9.59 +
9.60 +long PipePager::unsubscribe()
9.61 +{
9.62 + _paging->unsubscribe(_writing);
9.63 + return L4_EOK;
9.64 +}
9.65 +
9.66 // vim: tabstop=4 expandtab shiftwidth=4
10.1 --- a/libfsserver/lib/pipes/pipe_paging.cc Sat May 15 23:38:39 2021 +0200
10.2 +++ b/libfsserver/lib/pipes/pipe_paging.cc Tue May 18 00:55:20 2021 +0200
10.3 @@ -19,6 +19,10 @@
10.4 * Boston, MA 02110-1301, USA
10.5 */
10.6
10.7 +#include <l4/sys/irq.h>
10.8 +
10.9 +#include <ipc/cap_alloc.h>
10.10 +#include <ipc/irq.h>
10.11 #include <mem/memory_incremental.h>
10.12 #include <mem/memory_preallocated.h>
10.13
10.14 @@ -40,6 +44,48 @@
10.15
10.16 for (unsigned int i = 0; i < 2; i++)
10.17 _regions[i] = NULL;
10.18 +
10.19 + /* Initialise IRQ objects for notifications. */
10.20 +
10.21 + for (unsigned int i = 0; i < 2; i++)
10.22 + _irqs[i] = L4_INVALID_CAP;
10.23 +}
10.24 +
10.25 +/* Create an IRQ to subscribe to an endpoint's notifications. */
10.26 +
10.27 +l4_cap_idx_t PipePaging::subscribe(bool writing)
10.28 +{
10.29 + int i = writing ? 1 : 0;
10.30 +
10.31 + if (l4_is_invalid_cap(_irqs[i]))
10.32 + ipc_create_irq(&_irqs[i]);
10.33 +
10.34 + return _irqs[i];
10.35 +}
10.36 +
10.37 +/* Release any IRQ used for an endpoint's notifications. */
10.38 +
10.39 +void PipePaging::unsubscribe(bool writing)
10.40 +{
10.41 + int i = writing ? 1 : 0;
10.42 +
10.43 + if (l4_is_valid_cap(_irqs[i]))
10.44 + {
10.45 + ipc_cap_free_um(_irqs[i]);
10.46 + _irqs[i] = L4_INVALID_CAP;
10.47 + }
10.48 +}
10.49 +
10.50 +/* Notify the other endpoint. */
10.51 +
10.52 +void PipePaging::notify(bool writing)
10.53 +{
10.54 + /* Let the writer notify the reader, and the other way round. */
10.55 +
10.56 + int i = writing ? 0 : 1;
10.57 +
10.58 + if (l4_is_valid_cap(_irqs[i]))
10.59 + l4_irq_trigger(_irqs[i]);
10.60 }
10.61
10.62 /* Return whether one or more endpoints have detached. */
10.63 @@ -77,6 +123,17 @@
10.64 }
10.65 }
10.66
10.67 + /* Release IRQs. */
10.68 +
10.69 + for (unsigned int i = 0; i < 2; i++)
10.70 + {
10.71 + if (l4_is_valid_cap(_irqs[i]))
10.72 + {
10.73 + ipc_cap_free_um(_irqs[i]);
10.74 + _irqs[i] = L4_INVALID_CAP;
10.75 + }
10.76 + }
10.77 +
10.78 /* Delete the page collection and related objects. */
10.79
10.80 delete _pages;
10.81 @@ -108,6 +165,13 @@
10.82 mapper->set_data_size(0);
10.83
10.84 _regions[_writing] = mapper;
10.85 +
10.86 + /* Let the writer notify the reader. */
10.87 +
10.88 + notify(true);
10.89 +
10.90 + /* Return the next region's mapper. */
10.91 +
10.92 return mapper;
10.93 }
10.94
10.95 @@ -144,6 +208,10 @@
10.96
10.97 _reading = 1 - _reading;
10.98
10.99 + /* Let the reader notify the writer. */
10.100 +
10.101 + notify(false);
10.102 +
10.103 /* Return the next region's mapper. */
10.104
10.105 return _regions[_reading];
11.1 --- a/tests/dstest_pipe_client.cc Sat May 15 23:38:39 2021 +0200
11.2 +++ b/tests/dstest_pipe_client.cc Tue May 18 00:55:20 2021 +0200
11.3 @@ -22,6 +22,8 @@
11.4 #include <l4/re/env.h>
11.5 #include <l4/sys/err.h>
11.6
11.7 +#include <thread>
11.8 +
11.9 #include <stdio.h>
11.10 #include <string.h>
11.11 #include <stdlib.h>
11.12 @@ -32,8 +34,59 @@
11.13
11.14
11.15
11.16 +/* Minimum pipe region size in pages. */
11.17 +
11.18 const unsigned int PIPE_PAGES = 2;
11.19
11.20 +/* Use the writer to fill the pipe with data. */
11.21 +
11.22 +static void write_pipe(file_t *writer)
11.23 +{
11.24 + offset_t size = 600;
11.25 + char buffer[size];
11.26 +
11.27 + for (int loop = 0; loop < 3; loop++)
11.28 + {
11.29 + for (int region = 0; region < 26; region++)
11.30 + {
11.31 + memset(buffer, (int) 'a' + region, size);
11.32 +
11.33 + offset_t nwritten = client_write(writer, buffer, size);
11.34 +
11.35 + printf("Written %ld/%ld in #%d of %d/%d to pipe...\n", nwritten, size, region, loop, 2);
11.36 + }
11.37 + }
11.38 +
11.39 + /* Flush to make the final output available. */
11.40 +
11.41 + client_flush(writer);
11.42 +}
11.43 +
11.44 +/* Use the reader to obtain data from the pipe. */
11.45 +
11.46 +static void read_pipe(file_t *reader)
11.47 +{
11.48 + offset_t size = 600;
11.49 + char buffer[size];
11.50 + offset_t nread;
11.51 +
11.52 + do
11.53 + {
11.54 + nread = client_read(reader, buffer, size);
11.55 +
11.56 + printf("Read %ld/%ld from pipe...\n", nread, size);
11.57 +
11.58 + for (offset_t i = 0; i < nread; i += 60)
11.59 + {
11.60 + fwrite(buffer + i, sizeof(char), nread - i > 60 ? 60 : nread - i, stdout);
11.61 + fputs("\n", stdout);
11.62 + }
11.63 + }
11.64 + while (nread);
11.65 +
11.66 + printf("Data shown.\n");
11.67 +}
11.68 +
11.69 int main(void)
11.70 {
11.71 /* Obtain access to the filesystem. */
11.72 @@ -51,63 +104,23 @@
11.73 return 1;
11.74 }
11.75
11.76 - /* Use the writer to fill the pipe with data. */
11.77 -
11.78 - offset_t size = 600;
11.79 - char buffer[size];
11.80 - int region = 0;
11.81 -
11.82 - for (int loop = 0; loop < 3; loop++)
11.83 - {
11.84 - while (1)
11.85 - {
11.86 - printf("Writing %ld to pipe...\n", size);
11.87 -
11.88 - memset(buffer, (int) 'a' + region, size);
11.89 -
11.90 - offset_t nwritten = client_write(&writer, buffer, size);
11.91 -
11.92 - printf("Written %ld to pipe...\n", nwritten);
11.93 -
11.94 - for (offset_t i = 0; i < nwritten; i += 60)
11.95 - {
11.96 - fwrite(buffer + i, sizeof(char), nwritten - i > 60 ? 60 : nwritten - i, stdout);
11.97 - fputs("\n", stdout);
11.98 - }
11.99 + /* Make the reader and writer blocking to permit synchronisation. */
11.100
11.101 - if (!nwritten)
11.102 - break;
11.103 -
11.104 - region++;
11.105 -
11.106 - if (region == 26)
11.107 - region = 0;
11.108 - }
11.109 -
11.110 - /* Use the reader to obtain data from the pipe. */
11.111 -
11.112 - offset_t nread;
11.113 -
11.114 - do
11.115 - {
11.116 - printf("Reading %ld from pipe...\n", size);
11.117 -
11.118 - nread = client_read(&reader, buffer, size);
11.119 -
11.120 - printf("Read %ld from pipe...\n", nread);
11.121 -
11.122 - for (offset_t i = 0; i < nread; i += 60)
11.123 - {
11.124 - fwrite(buffer + i, sizeof(char), nread - i > 60 ? 60 : nread - i, stdout);
11.125 - fputs("\n", stdout);
11.126 - }
11.127 - }
11.128 - while (nread);
11.129 + if ((err = client_set_blocking(&reader, true)) || (err = client_set_blocking(&writer, true)))
11.130 + {
11.131 + printf("Could not set as blocking: %s\n", l4sys_errtostr(err));
11.132 + return 1;
11.133 }
11.134
11.135 - printf("Data shown.\n");
11.136 + /* Schedule reader and writer threads. */
11.137 +
11.138 + std::thread *activities[2];
11.139
11.140 - return 0;
11.141 + activities[0] = new std::thread(read_pipe, &reader);
11.142 + activities[1] = new std::thread(write_pipe, &writer);
11.143 +
11.144 + for (int i = 0; i < 2; i++)
11.145 + activities[i]->join();
11.146 }
11.147
11.148 // vim: tabstop=2 expandtab shiftwidth=2