1.1 --- a/docs/wiki/FilesystemAccess Mon Jun 27 16:30:51 2022 +0200
1.2 +++ b/docs/wiki/FilesystemAccess Tue Jun 28 01:02:14 2022 +0200
1.3 @@ -112,7 +112,7 @@
1.4 already open. The `ProviderRegistry` monitors the usage of files, discarding
1.5 any `Provider` no longer in use.
1.6
1.7 -== Opening a File ==
1.8 +== Opening Files ==
1.9
1.10 Opening a file involves the identification of the filesystem object involved,
1.11 the acquisition of a `Provider` representing the file, and the creation of a
1.12 @@ -211,27 +211,28 @@
1.13
1.14 Opener;
1.15
1.16 - ResourceRegistry [label="ResourceRegistry"];
1.17 + ResourceRegistry;
1.18
1.19 subgraph {
1.20 rank=same;
1.21
1.22 Provider_note [shape=note,style=filled,fillcolor=gold,label="Created\nand set in\nregistry"];
1.23 - Provider [label="Provider"];
1.24 + Provider;
1.25
1.26 - Accessor [label="Accessor"];
1.27 - Accessor_note [shape=note,style=filled,fillcolor=gold,label="Created\nfor provider"];
1.28 + Accessor;
1.29 + PageMapper;
1.30 + PageMapper_note [shape=note,style=filled,fillcolor=gold,label="Created\nfor provider"];
1.31
1.32 Provider_note -> Provider [dir=none,style=dotted];
1.33 - Accessor -> Accessor_note [dir=none,style=dotted];
1.34 + PageMapper -> PageMapper_note [dir=none,style=dotted];
1.35 }
1.36
1.37 subgraph {
1.38 rank=max;
1.39
1.40 ProviderRegistry_note [shape=note,style=filled,fillcolor=gold,label="Records\nopen files"];
1.41 - ProviderRegistry [label="ProviderRegistry"];
1.42 - FileOpening [label="FileOpening"];
1.43 + ProviderRegistry;
1.44 + FileOpening;
1.45 FileOpening_note [shape=note,style=filled,fillcolor=gold,label="Exposes\nfilesystem\nfunctionality"];
1.46
1.47 ProviderRegistry_note -> ProviderRegistry [dir=none,style=dotted];
1.48 @@ -244,7 +245,7 @@
1.49
1.50 ResourceRegistry -> FileOpening [label="make_accessor"];
1.51 FileOpening -> Accessor [dir=none];
1.52 - Accessor -> ResourceRegistry;
1.53 + Accessor -> PageMapper -> ResourceRegistry;
1.54
1.55 ResourceRegistry -> Provider [dir=none];
1.56 Provider -> ProviderRegistry [label="set(fileid)"];
1.57 @@ -252,3 +253,359 @@
1.58 }}}
1.59
1.60 ########
1.61 +
1.62 +== Notifications ==
1.63 +
1.64 +Within the filesystem access architecture, users of files may act in ways that
1.65 +may notify other users of the same file. To support such notifications, an
1.66 +interface is provided for filesystem clients to subscribe and unsubscribe to
1.67 +notifications. The notifications themselves occur when files are opened,
1.68 +modified and closed. Pipes also generate notifications when a pipe reader
1.69 +makes more space available for the writer.
1.70 +
1.71 +######## A graph showing subscription to notifications
1.72 +
1.73 +{{{#!graphviz
1.74 +#format svg
1.75 +#transform notugly
1.76 +digraph notification_subscriptions {
1.77 + node [fontsize="12.0",fontname="sans-serif",shape=box];
1.78 + edge [fontsize="12.0",fontname="sans-serif"];
1.79 + rankdir=LR;
1.80 +
1.81 + subgraph {
1.82 + rank=same;
1.83 +
1.84 + Client1 [label="Client\nprogram"];
1.85 + Client2 [label="Client\nprogram"];
1.86 + }
1.87 +
1.88 + subgraph {
1.89 + rank=same;
1.90 +
1.91 + Notifier1_note [shape=note,style=filled,fillcolor=gold,label="Created for\nnotifications"];
1.92 + Notifier1 [label="Notifier"];
1.93 + Notifier2 [label="Notifier"];
1.94 +
1.95 + Notifier1_note -> Notifier1 -> Notifier2 [dir=none,style=dotted];
1.96 + }
1.97 +
1.98 + subgraph {
1.99 + rank=same;
1.100 +
1.101 + Resource1 [label="Resource\n(Pager)"];
1.102 + Resource2 [label="Resource\n(Pager)"];
1.103 + }
1.104 +
1.105 + subgraph {
1.106 + rank=same;
1.107 +
1.108 + Notifier1_subscribe_note [shape=note,style=filled,fillcolor=gold,label="Propagated to\nprovider"];
1.109 + Notifier1_subscribe [label="Notifier"];
1.110 + Notifier2_subscribe [label="Notifier"];
1.111 +
1.112 + Notifier1_subscribe_note -> Notifier1_subscribe -> Notifier2_subscribe [dir=none,style=dotted];
1.113 + }
1.114 +
1.115 + subgraph {
1.116 + rank=same;
1.117 +
1.118 + Provider_note [shape=note,style=filled,fillcolor=gold,label="Manages file\nsubscriptions"];
1.119 + Provider [label="Provider"];
1.120 +
1.121 + Provider_note -> Provider [dir=none,style=dotted];
1.122 + }
1.123 +
1.124 + /* Subscribing. */
1.125 +
1.126 + Client1 -> Notifier1 [dir=none];
1.127 + Notifier1 -> Resource1 [label="subscribe"];
1.128 +
1.129 + Resource1 -> Notifier1_subscribe [dir=none];
1.130 + Notifier1_subscribe -> Provider [label="subscribe"];
1.131 +
1.132 + Client2 -> Notifier2 [dir=none];
1.133 + Notifier2 -> Resource2 [label="subscribe"];
1.134 +
1.135 + Resource2 -> Notifier2_subscribe [dir=none];
1.136 + Notifier2_subscribe -> Provider [label="subscribe"];
1.137 +}
1.138 +}}}
1.139 +
1.140 +########
1.141 +
1.142 +An example of a notification scenario is given below:
1.143 +
1.144 +######## A graph showing notification
1.145 +
1.146 +{{{#!graphviz
1.147 +#format svg
1.148 +#transform notugly
1.149 +digraph notifications {
1.150 + node [fontsize="12.0",fontname="sans-serif",shape=box];
1.151 + edge [fontsize="12.0",fontname="sans-serif"];
1.152 + rankdir=LR;
1.153 +
1.154 + subgraph {
1.155 + rank=same;
1.156 +
1.157 + Client1 [label="Client\nprogram"];
1.158 + Client2 [label="Client\nprogram"];
1.159 + }
1.160 +
1.161 + subgraph {
1.162 + rank=same;
1.163 +
1.164 + Notifier1_note [shape=note,style=filled,fillcolor=gold,label="Registered for\nnotifications"];
1.165 + Notifier1 [label="Notifier"];
1.166 +
1.167 + Resource2 [label="Resource\n(Pager)"];
1.168 + Resource2_note [shape=note,style=filled,fillcolor=gold,label="Generates\nnotification"];
1.169 +
1.170 + Notifier1_note -> Notifier1 [dir=none,style=dotted];
1.171 + Resource2 -> Resource2_note [dir=none,style=dotted];
1.172 + }
1.173 +
1.174 + subgraph {
1.175 + rank=same;
1.176 +
1.177 + Provider_note [shape=note,style=filled,fillcolor=gold,label="Propagates\nnotifications"];
1.178 + Provider [label="Provider"];
1.179 +
1.180 + Provider_note -> Provider [dir=none,style=dotted];
1.181 + }
1.182 +
1.183 + /* A notification scenario. */
1.184 +
1.185 + Client2 -> Resource2 [label="resize"];
1.186 + Resource2 -> Provider [label="notify_others"];
1.187 + Provider -> Notifier1 [label="notify"];
1.188 + Client1 -> Notifier1 [label="wait"];
1.189 +}
1.190 +}}}
1.191 +
1.192 +########
1.193 +
1.194 +Notifications provide the basis for blocking reading and writing operations,
1.195 +with pipe endpoints depending on such blocking for efficient use of pipes. The
1.196 +interactions involved when transferring data through pipes are depicted below.
1.197 +
1.198 +######## A graph showing notifications employed by pipe endpoints
1.199 +
1.200 +{{{#!graphviz
1.201 +#format svg
1.202 +#transform notugly
1.203 +digraph pipe_notifications {
1.204 + node [fontsize="12.0",fontname="sans-serif",shape=box];
1.205 + edge [fontsize="12.0",fontname="sans-serif"];
1.206 + rankdir=LR;
1.207 +
1.208 + subgraph {
1.209 + rank=min;
1.210 +
1.211 + Client1_note [shape=note,style=filled,fillcolor=gold,label="Fill pipe\nthen request\nmore space"];
1.212 + Client1 [label="Client\nprogram\n(writer)"];
1.213 + Client1_wait_note [shape=note,style=filled,fillcolor=gold,label="Waiting after\nfilling pipe"];
1.214 + Client1_wait [label="Client\nprogram\n(writer)"];
1.215 +
1.216 + Client1_note -> Client1 [dir=none,style=dotted];
1.217 + Client1_wait_note -> Client1_wait [dir=none,style=dotted];
1.218 +
1.219 + Client1 -> Client1_wait_note [dir=none,style=invis];
1.220 + }
1.221 +
1.222 + subgraph {
1.223 + rank=max;
1.224 +
1.225 + Client2_note [shape=note,style=filled,fillcolor=gold,label="Waiting for\nmore content\nbefore reading"];
1.226 + Client2 [label="Client\nprogram\n(reader)"];
1.227 + Client2_read_note [shape=note,style=filled,fillcolor=gold,label="Empty pipe\nthen request\nmore content"];
1.228 + Client2_read [label="Client\nprogram\n(reader)"];
1.229 +
1.230 + Client2_note -> Client2 [dir=none,style=dotted];
1.231 + Client2_read_note -> Client2_read [dir=none,style=dotted];
1.232 + }
1.233 +
1.234 + subgraph {
1.235 + rank=same;
1.236 +
1.237 + Notifier1 [label="Notifier"];
1.238 + Resource1 [label="Resource\n(PipePager)"];
1.239 + }
1.240 +
1.241 + subgraph {
1.242 + rank=same;
1.243 +
1.244 + Notifier2 [label="Notifier"];
1.245 + Resource2 [label="Resource\n(PipePager)"];
1.246 + }
1.247 +
1.248 + subgraph {
1.249 + rank=same;
1.250 +
1.251 + PipePaging [label="Provider\n(PipePaging)"];
1.252 + PipePaging_space [label="Provider\n(PipePaging)"];
1.253 + }
1.254 +
1.255 + /* Making content available. */
1.256 +
1.257 + Client1 -> Resource1 [label="next_region"];
1.258 + Resource1 -> PipePaging [label="add_region"];
1.259 + PipePaging -> Notifier2 [label="notify"];
1.260 + Client2 -> Notifier2 [label="wait"];
1.261 +
1.262 + /* Making space available. */
1.263 +
1.264 + Client2_read -> Resource2 [label="next_region"];
1.265 + Resource2 -> PipePaging_space [label="next_region"];
1.266 + PipePaging_space -> Notifier1 [label="notify"];
1.267 + Client1_wait -> Notifier1 [label="wait"];
1.268 +}
1.269 +}}}
1.270 +
1.271 +########
1.272 +
1.273 +== Closing Files ==
1.274 +
1.275 +Files are closed when client programs release their references to the resource
1.276 +capabilities used to access files. The mechanism by which this is done
1.277 +involves the registration of an IRQ object that is bound to the same thread as
1.278 +the one used by resources to service file access requests. This IRQ object is
1.279 +associated with the IPC gate through which such requests occur, and the IRQ
1.280 +object is configured to deliver an interrupt message when the final reference
1.281 +to the IPC gate has been released.
1.282 +
1.283 +When a client program terminates, its references to capabilities should be
1.284 +released, and this should cause a reference counter associated with the IPC
1.285 +gate to decrement. Upon the loss of the final reference and the delivery of
1.286 +the interrupt, the server framework will call a `close` method on the
1.287 +`Resource` object concerned, this implementing the
1.288 +[[ServerLibrary#Accountable|`Accountable`]] interface.
1.289 +
1.290 +######## A graph showing the closing mechanism
1.291 +
1.292 +{{{#!graphviz
1.293 +#format svg
1.294 +#transform notugly
1.295 +digraph closing {
1.296 + node [fontsize="12.0",fontname="sans-serif",shape=box];
1.297 + edge [fontsize="12.0",fontname="sans-serif"];
1.298 + rankdir=LR;
1.299 +
1.300 + Client [label="Client\nprogram"];
1.301 +
1.302 + subgraph {
1.303 + rank=same;
1.304 +
1.305 + Gate_note [shape=note,style=filled,fillcolor=gold,label="Actual\nendpoint"];
1.306 + Gate [label="IPC gate",shape="octagon"];
1.307 + IRQ [shape="triangle"];
1.308 + ResourceServer;
1.309 + ResourceServer_note [shape=note,style=filled,fillcolor=gold,label="Handles\nrequests"];
1.310 +
1.311 + Gate_note -> Gate [dir=none,style=dotted];
1.312 + ResourceServer -> ResourceServer_note [dir=none,style=dotted];
1.313 + }
1.314 +
1.315 + Resource [label="Resource\n(Pager)"];
1.316 +
1.317 + Provider;
1.318 +
1.319 + ProviderRegistry;
1.320 +
1.321 + Client -> Gate [style=dashed,label="(release)"];
1.322 + Gate -> IRQ -> ResourceServer;
1.323 + ResourceServer -> Resource [label="close"];
1.324 + Resource -> Provider [label="notify_others\nunsubscribe"];
1.325 + Resource -> ProviderRegistry [label="detach"];
1.326 +}
1.327 +}}}
1.328 +
1.329 +########
1.330 +
1.331 +As a consequence of closing a file, an `unsubscribe` operation performed on
1.332 +the `Provider` should cause any `Notifier` objects associated with the
1.333 +`Resource` object to be released. Meanwhile, the `ResourceServer` will discard
1.334 +the `Resource` object before the server thread terminates.
1.335 +
1.336 +== Removing Files ==
1.337 +
1.338 +Unix filesystem semantics typically allow a file to be "unlinked" while still
1.339 +being accessed by a program, with accesses still being directed to the file,
1.340 +but with the file being removed from a directory and potentially being
1.341 +replaced by another file. To support this, a mechanism is provided to defer
1.342 +any removal of an open file.
1.343 +
1.344 +######## A graph showing the removal mechanism
1.345 +
1.346 +{{{#!graphviz
1.347 +#format svg
1.348 +#transform notugly
1.349 +digraph removing {
1.350 + node [fontsize="12.0",fontname="sans-serif",shape=box];
1.351 + edge [fontsize="12.0",fontname="sans-serif"];
1.352 + rankdir=LR;
1.353 +
1.354 + subgraph {
1.355 + rank=same;
1.356 +
1.357 + Client1_note [shape=note,style=filled,fillcolor=gold,label="Removing\nopen file"];
1.358 + Client1 [label="Client\nprogram"];
1.359 + Client2 [label="Client\nprogram"];
1.360 + Client2_note [shape=note,style=filled,fillcolor=gold,label="Closes\nopen file"];
1.361 +
1.362 + Client1_note -> Client1 [dir=none,style=dotted];
1.363 + Client2 -> Client2_note [dir=none,style=dotted];
1.364 +
1.365 + Client1 -> Client2 [dir=none,style=invis];
1.366 + }
1.367 +
1.368 + subgraph {
1.369 + rank=same;
1.370 +
1.371 + Resource [label="Resource\n(Pager)"];
1.372 + Opener;
1.373 + }
1.374 +
1.375 + subgraph {
1.376 + rank=same;
1.377 +
1.378 + Provider1 [label="Provider"];
1.379 + Provider1_note [shape=note,style=filled,fillcolor=gold,label="Maintains\nremoval\nstate"];
1.380 + Provider2 [label="Provider"];
1.381 +
1.382 + Provider1 -> Provider1_note -> Provider2 [dir=none,style=dotted];
1.383 + }
1.384 +
1.385 + ProviderRegistry1 [label="ProviderRegistry"];
1.386 + ProviderRegistry2 [label="ProviderRegistry"];
1.387 +
1.388 + subgraph {
1.389 + rank=same;
1.390 +
1.391 + FileOpening;
1.392 + Accessor_note [shape=note,style=filled,fillcolor=gold,label="Performing\nfilesystem\noperations"];
1.393 + Accessor;
1.394 +
1.395 + FileOpening -> Accessor_note -> Accessor [dir=none,style=dotted];
1.396 + }
1.397 +
1.398 + /* Removing the file while it remains open. */
1.399 +
1.400 + Client1 -> Opener [label="remove\n(via context)"];
1.401 + Opener -> ResourceRegistry [label="remove_provider"];
1.402 + ResourceRegistry -> FileOpening [label="get_fileid\nunlink_object"];
1.403 + ResourceRegistry -> ProviderRegistry1 [label="get(fileid)"];
1.404 + ResourceRegistry -> Provider1 [label="remove_pending"];
1.405 +
1.406 + /* File closure and deferred removal. */
1.407 +
1.408 + Client2 -> Resource [label="close"];
1.409 + Resource -> Provider2 [label="notify_others\nunsubscribe"];
1.410 + Resource -> ProviderRegistry2 [label="detach"];
1.411 + ProviderRegistry2 -> Provider2 [label="remove"];
1.412 + Provider2 -> Accessor [label="remove"];
1.413 +}
1.414 +}}}
1.415 +
1.416 +########