1.1 --- a/docs/wiki/FilesystemAccess Wed Aug 10 23:58:38 2022 +0200
1.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
1.3 @@ -1,611 +0,0 @@
1.4 -= Filesystem Access =
1.5 -
1.6 -Within the [[ServerLibrary|filesystem server library]], a number of different
1.7 -abstractions and mechanisms are employed to provide access to filesystem
1.8 -objects. An overview of these abstractions is presented below.
1.9 -
1.10 -######## A graph showing the relationships between filesystem access
1.11 -######## components
1.12 -
1.13 -{{{#!graphviz
1.14 -#format svg
1.15 -#transform notugly
1.16 -digraph components {
1.17 - node [fontsize="12.0",fontname="sans-serif",shape=box];
1.18 - edge [fontsize="12.0",fontname="sans-serif"];
1.19 - rankdir=LR;
1.20 -
1.21 - subgraph {
1.22 - rank=same;
1.23 -
1.24 - Opener_note [shape=note,style=filled,fillcolor=gold,label="Exposes\nfile open\noperation"];
1.25 - Opener;
1.26 -
1.27 - Opener_note -> Opener [dir=none,style=dotted];
1.28 - }
1.29 -
1.30 - subgraph {
1.31 - rank=same;
1.32 -
1.33 - ResourceRegistry_note [shape=note,style=filled,fillcolor=gold,label="Records\nopen file\nsessions"];
1.34 - ResourceRegistry;
1.35 -
1.36 - ResourceRegistry_note -> ResourceRegistry [dir=none,style=dotted];
1.37 - }
1.38 -
1.39 - subgraph {
1.40 - rank=same;
1.41 -
1.42 - Resource_note [shape=note,style=filled,fillcolor=gold,label="Provides\nfilesystem\ncontent"];
1.43 - Resource [label="Resource\n(Pager)"];
1.44 -
1.45 - Resource_note -> Resource [dir=none,style=dotted];
1.46 - }
1.47 -
1.48 - subgraph {
1.49 - rank=same;
1.50 -
1.51 - Provider_note [shape=note,style=filled,fillcolor=gold,label="Represents\nopen file"];
1.52 - Provider;
1.53 -
1.54 - Provider_note -> Provider [dir=none,style=dotted];
1.55 - }
1.56 -
1.57 - subgraph {
1.58 - rank=same;
1.59 -
1.60 - PageMapper_note [shape=note,style=filled,fillcolor=gold,label="Provides\npopulated\nfile pages"];
1.61 - PageMapper;
1.62 -
1.63 - PageMapper_note -> PageMapper [dir=none,style=dotted];
1.64 - }
1.65 -
1.66 - ProviderRegistry [shape=record,label="<head> ProviderRegistry | ... | { file-n | provider-n } | ... "];
1.67 -
1.68 - subgraph {
1.69 - rank=same;
1.70 -
1.71 - FileOpening_note [shape=note,style=filled,fillcolor=gold,label="Exposes\nfilesystem\nfunctionality"];
1.72 - FileOpening;
1.73 -
1.74 - FileOpening_note -> FileOpening [dir=none,style=dotted];
1.75 - }
1.76 -
1.77 - subgraph {
1.78 - rank=same;
1.79 -
1.80 - Accessor_note [shape=note,style=filled,fillcolor=gold,label="Populates\nfile pages"];
1.81 - Accessor;
1.82 - Accessor_note -> Accessor [dir=none,style=dotted];
1.83 - }
1.84 -
1.85 - /* Opening a file. */
1.86 -
1.87 - Opener -> ResourceRegistry -> Resource;
1.88 - ResourceRegistry -> FileOpening;
1.89 -
1.90 - Provider -> PageMapper;
1.91 - FileOpening -> Accessor;
1.92 -
1.93 - /* Closing a file. */
1.94 -
1.95 - Resource -> Provider -> ProviderRegistry:head;
1.96 -
1.97 - /* Open file management. */
1.98 -
1.99 - ResourceRegistry -> ProviderRegistry:head;
1.100 -}
1.101 -}}}
1.102 -
1.103 -########
1.104 -
1.105 -An `Opener` requests a `Resource` from a `ResourceRegistry`, each `Resource`
1.106 -acting as a [[ServerLibrary#Pager|`Pager`]] and providing the actual access
1.107 -mechanism to file content for a particular program. Since many programs may
1.108 -access the same file simultaneously, a `Provider` object represents a file
1.109 -opened in the system, retaining a `PageMapper` that coordinates the collective
1.110 -access to the file (see the [[Paging|paging documentation]] for more
1.111 -information).
1.112 -
1.113 -A `ProviderRegistry` maintains the record of opened files, yielding a new
1.114 -`Provider` for an unopened file or an existing `Provider` for a file that is
1.115 -already open. The `ProviderRegistry` monitors the usage of files, discarding
1.116 -any `Provider` no longer in use.
1.117 -
1.118 -== Opening Files ==
1.119 -
1.120 -Opening a file involves the identification of the filesystem object involved,
1.121 -the acquisition of a `Provider` representing the file, and the creation of a
1.122 -`Resource` to deliver file content to the requesting program.
1.123 -
1.124 -######## A graph showing the opening mechanism for an already-open file
1.125 -
1.126 -{{{#!graphviz
1.127 -#format svg
1.128 -#transform notugly
1.129 -digraph opening_open {
1.130 - node [fontsize="12.0",fontname="sans-serif",shape=box];
1.131 - edge [fontsize="12.0",fontname="sans-serif"];
1.132 - rankdir=LR;
1.133 -
1.134 - subgraph {
1.135 - rank=same;
1.136 -
1.137 - Opener_note [shape=note,style=filled,fillcolor=gold,label="Exposes\nfile open\noperation"];
1.138 - Opener;
1.139 -
1.140 - Opener_note -> Opener [dir=none,style=dotted];
1.141 - }
1.142 -
1.143 - subgraph {
1.144 - rank=same;
1.145 -
1.146 - ResourceRegistry_note [shape=note,style=filled,fillcolor=gold,label="Records\nopen file\nsessions"];
1.147 - ResourceRegistry;
1.148 -
1.149 - Resource_returned [label="Resource\n(Pager)"];
1.150 - Resource_returned_note [shape=note,style=filled,fillcolor=gold,label="Provides\nfilesystem\ncontent"];
1.151 -
1.152 - ResourceRegistry_note -> ResourceRegistry [dir=none,style=dotted];
1.153 - Resource_returned -> Resource_returned_note [dir=none,style=dotted];
1.154 - }
1.155 -
1.156 - subgraph {
1.157 - rank=same;
1.158 -
1.159 - Resource [label="Resource\n(Pager)"];
1.160 -
1.161 - FileOpening_note [shape=note,style=filled,fillcolor=gold,label="Exposes\nfilesystem\nfunctionality"];
1.162 - FileOpening;
1.163 -
1.164 - FileOpening_note -> FileOpening [dir=none,style=dotted];
1.165 - }
1.166 -
1.167 - subgraph {
1.168 - rank=max;
1.169 -
1.170 - ProviderRegistry_note [shape=note,style=filled,fillcolor=gold,label="Provides\nopen files"];
1.171 - ProviderRegistry;
1.172 -
1.173 - Provider;
1.174 - Provider_note [shape=note,style=filled,fillcolor=gold,label="Represents\nopen file"];
1.175 -
1.176 - ProviderRegistry_note -> ProviderRegistry [dir=none,style=dotted];
1.177 - Provider -> Provider_note [dir=none,style=dotted];
1.178 - }
1.179 -
1.180 - /* Obtaining a resource from the registry. */
1.181 -
1.182 - Opener -> ResourceRegistry [label="get_resource"];
1.183 - ResourceRegistry -> Resource_returned [dir=none];
1.184 - Resource_returned -> Opener;
1.185 -
1.186 - /* Obtaining a provider. */
1.187 -
1.188 - ResourceRegistry -> FileOpening [label="get_fileid"];
1.189 - ResourceRegistry -> ProviderRegistry [label="get(fileid)"];
1.190 - ProviderRegistry -> Provider;
1.191 -
1.192 - /* Obtaining the resource from the provider. */
1.193 -
1.194 - ResourceRegistry -> Provider [label="make_resource"];
1.195 - Provider -> Resource [dir=none];
1.196 - Resource -> ResourceRegistry;
1.197 -}
1.198 -}}}
1.199 -
1.200 -########
1.201 -
1.202 -Where a provider does not already exist, with the file not having been opened
1.203 -already, some extra interactions occur:
1.204 -
1.205 -######## A graph showing opening mechanism details for an unopened file
1.206 -
1.207 -{{{#!graphviz
1.208 -#format svg
1.209 -#transform notugly
1.210 -digraph opening_unopened {
1.211 - node [fontsize="12.0",fontname="sans-serif",shape=box];
1.212 - edge [fontsize="12.0",fontname="sans-serif"];
1.213 - rankdir=LR;
1.214 -
1.215 - Opener;
1.216 -
1.217 - ResourceRegistry;
1.218 -
1.219 - subgraph {
1.220 - rank=same;
1.221 -
1.222 - Provider_note [shape=note,style=filled,fillcolor=gold,label="Created\nand set in\nregistry"];
1.223 - Provider;
1.224 -
1.225 - Accessor;
1.226 - PageMapper;
1.227 - PageMapper_note [shape=note,style=filled,fillcolor=gold,label="Created\nfor provider"];
1.228 -
1.229 - Provider_note -> Provider [dir=none,style=dotted];
1.230 - PageMapper -> PageMapper_note [dir=none,style=dotted];
1.231 - }
1.232 -
1.233 - subgraph {
1.234 - rank=max;
1.235 -
1.236 - ProviderRegistry_note [shape=note,style=filled,fillcolor=gold,label="Records\nopen files"];
1.237 - ProviderRegistry;
1.238 - FileOpening;
1.239 - FileOpening_note [shape=note,style=filled,fillcolor=gold,label="Exposes\nfilesystem\nfunctionality"];
1.240 -
1.241 - ProviderRegistry_note -> ProviderRegistry [dir=none,style=dotted];
1.242 - FileOpening -> FileOpening_note [dir=none,style=dotted];
1.243 - }
1.244 -
1.245 - Opener -> ResourceRegistry [dir=none,style=dashed];
1.246 -
1.247 - /* Obtaining a new provider. */
1.248 -
1.249 - ResourceRegistry -> FileOpening [label="make_accessor"];
1.250 - FileOpening -> Accessor [dir=none];
1.251 - Accessor -> PageMapper -> ResourceRegistry;
1.252 -
1.253 - ResourceRegistry -> Provider [dir=none];
1.254 - Provider -> ProviderRegistry [label="set(fileid)"];
1.255 -}
1.256 -}}}
1.257 -
1.258 -########
1.259 -
1.260 -== Notifications ==
1.261 -
1.262 -Within the filesystem access architecture, users of files may act in ways that
1.263 -may notify other users of the same file. To support such notifications, an
1.264 -interface is provided for filesystem clients to subscribe and unsubscribe to
1.265 -notifications. The notifications themselves occur when files are opened,
1.266 -modified and closed. Pipes also generate notifications when a pipe reader
1.267 -makes more space available for the writer.
1.268 -
1.269 -######## A graph showing subscription to notifications
1.270 -
1.271 -{{{#!graphviz
1.272 -#format svg
1.273 -#transform notugly
1.274 -digraph notification_subscriptions {
1.275 - node [fontsize="12.0",fontname="sans-serif",shape=box];
1.276 - edge [fontsize="12.0",fontname="sans-serif"];
1.277 - rankdir=LR;
1.278 -
1.279 - subgraph {
1.280 - rank=same;
1.281 -
1.282 - Client1 [label="Client\nprogram"];
1.283 - Client2 [label="Client\nprogram"];
1.284 - }
1.285 -
1.286 - subgraph {
1.287 - rank=same;
1.288 -
1.289 - Notifier1_note [shape=note,style=filled,fillcolor=gold,label="Created for\nnotifications"];
1.290 - Notifier1 [label="Notifier"];
1.291 - Notifier2 [label="Notifier"];
1.292 -
1.293 - Notifier1_note -> Notifier1 -> Notifier2 [dir=none,style=dotted];
1.294 - }
1.295 -
1.296 - subgraph {
1.297 - rank=same;
1.298 -
1.299 - Resource1 [label="Resource\n(Pager)"];
1.300 - Resource2 [label="Resource\n(Pager)"];
1.301 - }
1.302 -
1.303 - subgraph {
1.304 - rank=same;
1.305 -
1.306 - Notifier1_subscribe_note [shape=note,style=filled,fillcolor=gold,label="Propagated to\nprovider"];
1.307 - Notifier1_subscribe [label="Notifier"];
1.308 - Notifier2_subscribe [label="Notifier"];
1.309 -
1.310 - Notifier1_subscribe_note -> Notifier1_subscribe -> Notifier2_subscribe [dir=none,style=dotted];
1.311 - }
1.312 -
1.313 - subgraph {
1.314 - rank=same;
1.315 -
1.316 - Provider_note [shape=note,style=filled,fillcolor=gold,label="Manages file\nsubscriptions"];
1.317 - Provider [label="Provider"];
1.318 -
1.319 - Provider_note -> Provider [dir=none,style=dotted];
1.320 - }
1.321 -
1.322 - /* Subscribing. */
1.323 -
1.324 - Client1 -> Notifier1 [dir=none];
1.325 - Notifier1 -> Resource1 [label="subscribe"];
1.326 -
1.327 - Resource1 -> Notifier1_subscribe [dir=none];
1.328 - Notifier1_subscribe -> Provider [label="subscribe"];
1.329 -
1.330 - Client2 -> Notifier2 [dir=none];
1.331 - Notifier2 -> Resource2 [label="subscribe"];
1.332 -
1.333 - Resource2 -> Notifier2_subscribe [dir=none];
1.334 - Notifier2_subscribe -> Provider [label="subscribe"];
1.335 -}
1.336 -}}}
1.337 -
1.338 -########
1.339 -
1.340 -An example of a notification scenario is given below:
1.341 -
1.342 -######## A graph showing notification
1.343 -
1.344 -{{{#!graphviz
1.345 -#format svg
1.346 -#transform notugly
1.347 -digraph notifications {
1.348 - node [fontsize="12.0",fontname="sans-serif",shape=box];
1.349 - edge [fontsize="12.0",fontname="sans-serif"];
1.350 - rankdir=LR;
1.351 -
1.352 - subgraph {
1.353 - rank=same;
1.354 -
1.355 - Client1 [label="Client\nprogram"];
1.356 - Client2 [label="Client\nprogram"];
1.357 - }
1.358 -
1.359 - subgraph {
1.360 - rank=same;
1.361 -
1.362 - Notifier1_note [shape=note,style=filled,fillcolor=gold,label="Registered for\nnotifications"];
1.363 - Notifier1 [label="Notifier"];
1.364 -
1.365 - Resource2 [label="Resource\n(Pager)"];
1.366 - Resource2_note [shape=note,style=filled,fillcolor=gold,label="Generates\nnotification"];
1.367 -
1.368 - Notifier1_note -> Notifier1 [dir=none,style=dotted];
1.369 - Resource2 -> Resource2_note [dir=none,style=dotted];
1.370 - }
1.371 -
1.372 - subgraph {
1.373 - rank=same;
1.374 -
1.375 - Provider_note [shape=note,style=filled,fillcolor=gold,label="Propagates\nnotifications"];
1.376 - Provider [label="Provider"];
1.377 -
1.378 - Provider_note -> Provider [dir=none,style=dotted];
1.379 - }
1.380 -
1.381 - /* A notification scenario. */
1.382 -
1.383 - Client2 -> Resource2 [label="resize"];
1.384 - Resource2 -> Provider [label="notify_others"];
1.385 - Provider -> Notifier1 [label="notify"];
1.386 - Client1 -> Notifier1 [label="wait"];
1.387 -}
1.388 -}}}
1.389 -
1.390 -########
1.391 -
1.392 -Notifications provide the basis for blocking reading and writing operations,
1.393 -with pipe endpoints depending on such blocking for efficient use of pipes. The
1.394 -interactions involved when transferring data through pipes are depicted below.
1.395 -
1.396 -######## A graph showing notifications employed by pipe endpoints
1.397 -
1.398 -{{{#!graphviz
1.399 -#format svg
1.400 -#transform notugly
1.401 -digraph pipe_notifications {
1.402 - node [fontsize="12.0",fontname="sans-serif",shape=box];
1.403 - edge [fontsize="12.0",fontname="sans-serif"];
1.404 - rankdir=LR;
1.405 -
1.406 - subgraph {
1.407 - rank=min;
1.408 -
1.409 - Client1_note [shape=note,style=filled,fillcolor=gold,label="Fill pipe\nthen request\nmore space"];
1.410 - Client1 [label="Client\nprogram\n(writer)"];
1.411 - Client1_wait_note [shape=note,style=filled,fillcolor=gold,label="Waiting after\nfilling pipe"];
1.412 - Client1_wait [label="Client\nprogram\n(writer)"];
1.413 -
1.414 - Client1_note -> Client1 [dir=none,style=dotted];
1.415 - Client1_wait_note -> Client1_wait [dir=none,style=dotted];
1.416 -
1.417 - Client1 -> Client1_wait_note [dir=none,style=invis];
1.418 - }
1.419 -
1.420 - subgraph {
1.421 - rank=max;
1.422 -
1.423 - Client2_note [shape=note,style=filled,fillcolor=gold,label="Waiting for\nmore content\nbefore reading"];
1.424 - Client2 [label="Client\nprogram\n(reader)"];
1.425 - Client2_read_note [shape=note,style=filled,fillcolor=gold,label="Empty pipe\nthen request\nmore content"];
1.426 - Client2_read [label="Client\nprogram\n(reader)"];
1.427 -
1.428 - Client2_note -> Client2 [dir=none,style=dotted];
1.429 - Client2_read_note -> Client2_read [dir=none,style=dotted];
1.430 - }
1.431 -
1.432 - subgraph {
1.433 - rank=same;
1.434 -
1.435 - Notifier1 [label="Notifier"];
1.436 - Resource1 [label="Resource\n(PipePager)"];
1.437 - }
1.438 -
1.439 - subgraph {
1.440 - rank=same;
1.441 -
1.442 - Notifier2 [label="Notifier"];
1.443 - Resource2 [label="Resource\n(PipePager)"];
1.444 - }
1.445 -
1.446 - subgraph {
1.447 - rank=same;
1.448 -
1.449 - PipePaging [label="Provider\n(PipePaging)"];
1.450 - PipePaging_space [label="Provider\n(PipePaging)"];
1.451 - }
1.452 -
1.453 - /* Making content available. */
1.454 -
1.455 - Client1 -> Resource1 [label="next_region"];
1.456 - Resource1 -> PipePaging [label="add_region"];
1.457 - PipePaging -> Notifier2 [label="notify"];
1.458 - Client2 -> Notifier2 [label="wait"];
1.459 -
1.460 - /* Making space available. */
1.461 -
1.462 - Client2_read -> Resource2 [label="next_region"];
1.463 - Resource2 -> PipePaging_space [label="next_region"];
1.464 - PipePaging_space -> Notifier1 [label="notify"];
1.465 - Client1_wait -> Notifier1 [label="wait"];
1.466 -}
1.467 -}}}
1.468 -
1.469 -########
1.470 -
1.471 -== Closing Files ==
1.472 -
1.473 -Files are closed when client programs release their references to the resource
1.474 -capabilities used to access files. The mechanism by which this is done
1.475 -involves the registration of an IRQ object that is bound to the same thread as
1.476 -the one used by resources to service file access requests. This IRQ object is
1.477 -associated with the IPC gate through which such requests occur, and the IRQ
1.478 -object is configured to deliver an interrupt message when the final reference
1.479 -to the IPC gate has been released.
1.480 -
1.481 -When a client program terminates, its references to capabilities should be
1.482 -released, and this should cause a reference counter associated with the IPC
1.483 -gate to decrement. Upon the loss of the final reference and the delivery of
1.484 -the interrupt, the server framework will call a `close` method on the
1.485 -`Resource` object concerned, this implementing the
1.486 -[[ServerLibrary#Accountable|`Accountable`]] interface.
1.487 -
1.488 -######## A graph showing the closing mechanism
1.489 -
1.490 -{{{#!graphviz
1.491 -#format svg
1.492 -#transform notugly
1.493 -digraph closing {
1.494 - node [fontsize="12.0",fontname="sans-serif",shape=box];
1.495 - edge [fontsize="12.0",fontname="sans-serif"];
1.496 - rankdir=LR;
1.497 -
1.498 - Client [label="Client\nprogram"];
1.499 -
1.500 - subgraph {
1.501 - rank=same;
1.502 -
1.503 - Gate_note [shape=note,style=filled,fillcolor=gold,label="Actual\nendpoint"];
1.504 - Gate [label="IPC gate",shape="octagon"];
1.505 - IRQ [shape="triangle"];
1.506 - ResourceServer;
1.507 - ResourceServer_note [shape=note,style=filled,fillcolor=gold,label="Handles\nrequests"];
1.508 -
1.509 - Gate_note -> Gate [dir=none,style=dotted];
1.510 - ResourceServer -> ResourceServer_note [dir=none,style=dotted];
1.511 - }
1.512 -
1.513 - Resource [label="Resource\n(Pager)"];
1.514 -
1.515 - Provider;
1.516 -
1.517 - ProviderRegistry;
1.518 -
1.519 - Client -> Gate [style=dashed,label="(release)"];
1.520 - Gate -> IRQ -> ResourceServer;
1.521 - ResourceServer -> Resource [label="close"];
1.522 - Resource -> Provider [label="notify_others\nunsubscribe"];
1.523 - Resource -> ProviderRegistry [label="detach"];
1.524 -}
1.525 -}}}
1.526 -
1.527 -########
1.528 -
1.529 -As a consequence of closing a file, an `unsubscribe` operation performed on
1.530 -the `Provider` should cause any `Notifier` objects associated with the
1.531 -`Resource` object to be released. Meanwhile, the `ResourceServer` will discard
1.532 -the `Resource` object before the server thread terminates.
1.533 -
1.534 -== Removing Files ==
1.535 -
1.536 -Unix filesystem semantics typically allow a file to be "unlinked" while still
1.537 -being accessed by a program, with accesses still being directed to the file,
1.538 -but with the file being removed from a directory and potentially being
1.539 -replaced by another file. To support this, a mechanism is provided to defer
1.540 -any removal of an open file.
1.541 -
1.542 -######## A graph showing the removal mechanism
1.543 -
1.544 -{{{#!graphviz
1.545 -#format svg
1.546 -#transform notugly
1.547 -digraph removing {
1.548 - node [fontsize="12.0",fontname="sans-serif",shape=box];
1.549 - edge [fontsize="12.0",fontname="sans-serif"];
1.550 - rankdir=LR;
1.551 -
1.552 - subgraph {
1.553 - rank=same;
1.554 -
1.555 - Client1_note [shape=note,style=filled,fillcolor=gold,label="Removing\nopen file"];
1.556 - Client1 [label="Client\nprogram"];
1.557 - Client2 [label="Client\nprogram"];
1.558 - Client2_note [shape=note,style=filled,fillcolor=gold,label="Closes\nopen file"];
1.559 -
1.560 - Client1_note -> Client1 [dir=none,style=dotted];
1.561 - Client2 -> Client2_note [dir=none,style=dotted];
1.562 -
1.563 - Client1 -> Client2 [dir=none,style=invis];
1.564 - }
1.565 -
1.566 - subgraph {
1.567 - rank=same;
1.568 -
1.569 - Resource [label="Resource\n(Pager)"];
1.570 - Opener;
1.571 - }
1.572 -
1.573 - subgraph {
1.574 - rank=same;
1.575 -
1.576 - Provider1 [label="Provider"];
1.577 - Provider1_note [shape=note,style=filled,fillcolor=gold,label="Maintains\nremoval\nstate"];
1.578 - Provider2 [label="Provider"];
1.579 -
1.580 - Provider1 -> Provider1_note -> Provider2 [dir=none,style=dotted];
1.581 - }
1.582 -
1.583 - ProviderRegistry1 [label="ProviderRegistry"];
1.584 - ProviderRegistry2 [label="ProviderRegistry"];
1.585 -
1.586 - subgraph {
1.587 - rank=same;
1.588 -
1.589 - FileOpening;
1.590 - Accessor_note [shape=note,style=filled,fillcolor=gold,label="Performing\nfilesystem\noperations"];
1.591 - Accessor;
1.592 -
1.593 - FileOpening -> Accessor_note -> Accessor [dir=none,style=dotted];
1.594 - }
1.595 -
1.596 - /* Removing the file while it remains open. */
1.597 -
1.598 - Client1 -> Opener [label="remove\n(via context)"];
1.599 - Opener -> ResourceRegistry [label="remove_provider"];
1.600 - ResourceRegistry -> FileOpening [label="get_fileid\nunlink_object"];
1.601 - ResourceRegistry -> ProviderRegistry1 [label="get(fileid)"];
1.602 - ResourceRegistry -> Provider1 [label="remove_pending"];
1.603 -
1.604 - /* File closure and deferred removal. */
1.605 -
1.606 - Client2 -> Resource [label="close"];
1.607 - Resource -> Provider2 [label="notify_others\nunsubscribe"];
1.608 - Resource -> ProviderRegistry2 [label="detach"];
1.609 - ProviderRegistry2 -> Provider2 [label="remove"];
1.610 - Provider2 -> Accessor [label="remove"];
1.611 -}
1.612 -}}}
1.613 -
1.614 -########