# HG changeset patch # User Paul Boddie # Date 1660315266 -7200 # Node ID f7c8fe9d968f683581850315539199acc2f773aa # Parent 8306354f755bee52685282c9dfd33d3090ffcb6a Renamed the main page to Departure and changed the page naming convention. diff -r 8306354f755b -r f7c8fe9d968f docs/wiki/ClientLibrary --- a/docs/wiki/ClientLibrary Wed Aug 10 23:58:38 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,148 +0,0 @@ -= Client Library = - -The filesystem client library offers abstractions and a number of layers of -functionality to support interaction with [[Components|components]] and the -provision of higher-level mechanisms and abstractions for file access. - -<> - -== File Data Structures == - -Since files are accessed using file references, the `file_t` data structure is -used to wrap such references and other relevant state. Thus, such structures -can be broadly regarded as similar to the traditional `FILE` data structure. - -The fields of the `file_t` data structure are as follows: - -|| '''Field''' || '''Description''' || -|| `ref` || A reference to the component providing file content || -|| `memory` || The memory address of the exposed file region || -|| `start_pos` || The start position of the region in the file || -|| `end_pos` || The end position of the region in the file || -|| `data_end` || The amount or extent of populated data in the region || -|| `data_current` || The offset used to track client position in the region || -|| `size` || The total size of the file || -|| `object_flags` || Flags indicating support for certain file features || -|| `can_block` || Notification flags for blocking access to the file || -|| `notifications`|| Notification flags set for the file || -|| `flags` || The flags used to open the file || - -== Client Programming Interface == - -The client programming interface provides functions somewhat resembling the -traditional C library and low-level Unix interfaces for file access, and these -functions are intended to support such traditional interfaces. - -=== Files === - -Files are opened and closed using the following functions: - -{{{ -file_t *client_open(const char *name, flags_t flags); -}}} - -Each file endpoint may be closed using `client_close`. - -=== Pipes === - -Pipes are opened using a special function: - -{{{ -long client_pipe(file_t **reader, file_t **writer, flags_t flags); -}}} - -Each pipe endpoint may be closed using `client_close`. - -=== Closing Files and Pipes === - -Closing files and pipes involves a common operation: - -{{{ -void client_close(file_t *file); -}}} - -When client programs terminate, the freeing of their object capabilities -should cause the closure of files and pipes, but programs may choose to close -such resources explicitly. - -=== Reading and Writing === - -Reading and writing files and pipes involves functions resembling the -traditional low-level `read` and `write` functions: - -{{{ -offset_t client_read(file_t *file, void *buf, offset_t count); -offset_t client_write(file_t *file, const void *buf, offset_t count); -}}} - -=== Navigation in Files === - -Support for navigation in files is provided using functions resembling the -traditional higher-level `fseek` and `ftell` functions: - -{{{ -offset_t client_seek(file_t *file, offset_t offset, int whence); -long client_tell(file_t *file); -}}} - -=== Accessing Exposed Memory Regions === - -Although the client library (and the provision of files) employs mapped -memory, a function can be used to explicitly reference memory for file access: - -{{{ -void *client_mmap(file_t *file, offset_t position, offset_t length); -}}} - -Pipes support a different mechanism for navigation involving the following -functions: - -{{{ -long client_current_region(file_t *file); -long client_next_region(file_t *file); -}}} - -Such navigation functions for files and pipes do not need to be used where the -higher-level reading, writing and seeking functions are in use. - -=== Flushing and Synchronisation === - -For synchronisation purposes, either with the filesystem itself or with other -users of the filesystem, a function resembling the traditional `fflush` -function is provided: - -{{{ -long client_flush(file_t *file); -}}} - -This updates the file data structure with new details of the file size, also -updating any altered details of the extent of the data in the currently -accessed region of the file. - -=== Notifications === - -Since files and pipes may be accessed by multiple clients, necessarily for any -sensible use of the latter, notifications can be configured to communicate a -change in state to other users of these resources when they are accessed. - -Notification types are specified using values encoding a number of flags, and -the following flags are available for this purpose: - -|| '''Flag''' || '''Notification Type''' || -|| `NOTIFY_CONTENT_AVAILABLE` || Content available to read || -|| `NOTIFY_PEER_CLOSED` || Other party has closed their endpoint || -|| `NOTIFY_SPACE_AVAILABLE` || Space available for writing || - -=== Blocking Operations === - -Reading and writing operations can be configured to block if data cannot be -read or written respectively. The following function is provided for this -purpose: - -{{{ -long client_set_blocking(file_t *file, notify_flags_t flags); -}}} - -For pipes, blocking behaviour is the default and must be disabled explicitly, -either by opening using the `O_NONBLOCK` flag or by calling -`client_set_blocking` with no flags set. diff -r 8306354f755b -r f7c8fe9d968f docs/wiki/Client_Library --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/docs/wiki/Client_Library Fri Aug 12 16:41:06 2022 +0200 @@ -0,0 +1,148 @@ += Client Library = + +The filesystem client library offers abstractions and a number of layers of +functionality to support interaction with [[Components|components]] and the +provision of higher-level mechanisms and abstractions for file access. + +<> + +== File Data Structures == + +Since files are accessed using file references, the `file_t` data structure is +used to wrap such references and other relevant state. Thus, such structures +can be broadly regarded as similar to the traditional `FILE` data structure. + +The fields of the `file_t` data structure are as follows: + +|| '''Field''' || '''Description''' || +|| `ref` || A reference to the component providing file content || +|| `memory` || The memory address of the exposed file region || +|| `start_pos` || The start position of the region in the file || +|| `end_pos` || The end position of the region in the file || +|| `data_end` || The amount or extent of populated data in the region || +|| `data_current` || The offset used to track client position in the region || +|| `size` || The total size of the file || +|| `object_flags` || Flags indicating support for certain file features || +|| `can_block` || Notification flags for blocking access to the file || +|| `notifications`|| Notification flags set for the file || +|| `flags` || The flags used to open the file || + +== Client Programming Interface == + +The client programming interface provides functions somewhat resembling the +traditional C library and low-level Unix interfaces for file access, and these +functions are intended to support such traditional interfaces. + +=== Files === + +Files are opened and closed using the following functions: + +{{{ +file_t *client_open(const char *name, flags_t flags); +}}} + +Each file endpoint may be closed using `client_close`. + +=== Pipes === + +Pipes are opened using a special function: + +{{{ +long client_pipe(file_t **reader, file_t **writer, flags_t flags); +}}} + +Each pipe endpoint may be closed using `client_close`. + +=== Closing Files and Pipes === + +Closing files and pipes involves a common operation: + +{{{ +void client_close(file_t *file); +}}} + +When client programs terminate, the freeing of their object capabilities +should cause the closure of files and pipes, but programs may choose to close +such resources explicitly. + +=== Reading and Writing === + +Reading and writing files and pipes involves functions resembling the +traditional low-level `read` and `write` functions: + +{{{ +offset_t client_read(file_t *file, void *buf, offset_t count); +offset_t client_write(file_t *file, const void *buf, offset_t count); +}}} + +=== Navigation in Files === + +Support for navigation in files is provided using functions resembling the +traditional higher-level `fseek` and `ftell` functions: + +{{{ +offset_t client_seek(file_t *file, offset_t offset, int whence); +long client_tell(file_t *file); +}}} + +=== Accessing Exposed Memory Regions === + +Although the client library (and the provision of files) employs mapped +memory, a function can be used to explicitly reference memory for file access: + +{{{ +void *client_mmap(file_t *file, offset_t position, offset_t length); +}}} + +Pipes support a different mechanism for navigation involving the following +functions: + +{{{ +long client_current_region(file_t *file); +long client_next_region(file_t *file); +}}} + +Such navigation functions for files and pipes do not need to be used where the +higher-level reading, writing and seeking functions are in use. + +=== Flushing and Synchronisation === + +For synchronisation purposes, either with the filesystem itself or with other +users of the filesystem, a function resembling the traditional `fflush` +function is provided: + +{{{ +long client_flush(file_t *file); +}}} + +This updates the file data structure with new details of the file size, also +updating any altered details of the extent of the data in the currently +accessed region of the file. + +=== Notifications === + +Since files and pipes may be accessed by multiple clients, necessarily for any +sensible use of the latter, notifications can be configured to communicate a +change in state to other users of these resources when they are accessed. + +Notification types are specified using values encoding a number of flags, and +the following flags are available for this purpose: + +|| '''Flag''' || '''Notification Type''' || +|| `NOTIFY_CONTENT_AVAILABLE` || Content available to read || +|| `NOTIFY_PEER_CLOSED` || Other party has closed their endpoint || +|| `NOTIFY_SPACE_AVAILABLE` || Space available for writing || + +=== Blocking Operations === + +Reading and writing operations can be configured to block if data cannot be +read or written respectively. The following function is provided for this +purpose: + +{{{ +long client_set_blocking(file_t *file, notify_flags_t flags); +}}} + +For pipes, blocking behaviour is the default and must be disabled explicitly, +either by opening using the `O_NONBLOCK` flag or by calling +`client_set_blocking` with no flags set. diff -r 8306354f755b -r f7c8fe9d968f docs/wiki/Departure --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/docs/wiki/Departure Fri Aug 12 16:41:06 2022 +0200 @@ -0,0 +1,21 @@ += Departure = + +The Departure distribution aims to provide components and libraries to +implement and deliver filesystem access in the L4 Runtime Environment. In +particular, it acts as a research and testing vehicle for implementations of +demand-paged files. + +== Topics == + + * [[Client Library]] - convenience functions and structures to access + filesystem objects + * [[Components]] - server objects exposed at the system level that support + filesystem access + * [[Filesystem Access]] - mechanisms within filesystem servers to manage + filesystem resources and content + * [[Paging]] - the mechanism by which filesystem content is provided for use + by client programs + * [[Program Loading]] - the mechanism by which programs are loaded + * [[Server Library]] - abstractions to expose and manage access to filesystem + objects + * [[Users]] diff -r 8306354f755b -r f7c8fe9d968f docs/wiki/FilesystemAccess --- a/docs/wiki/FilesystemAccess Wed Aug 10 23:58:38 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,611 +0,0 @@ -= Filesystem Access = - -Within the [[ServerLibrary|filesystem server library]], a number of different -abstractions and mechanisms are employed to provide access to filesystem -objects. An overview of these abstractions is presented below. - -######## A graph showing the relationships between filesystem access -######## components - -{{{#!graphviz -#format svg -#transform notugly -digraph components { - node [fontsize="12.0",fontname="sans-serif",shape=box]; - edge [fontsize="12.0",fontname="sans-serif"]; - rankdir=LR; - - subgraph { - rank=same; - - Opener_note [shape=note,style=filled,fillcolor=gold,label="Exposes\nfile open\noperation"]; - Opener; - - Opener_note -> Opener [dir=none,style=dotted]; - } - - subgraph { - rank=same; - - ResourceRegistry_note [shape=note,style=filled,fillcolor=gold,label="Records\nopen file\nsessions"]; - ResourceRegistry; - - ResourceRegistry_note -> ResourceRegistry [dir=none,style=dotted]; - } - - subgraph { - rank=same; - - Resource_note [shape=note,style=filled,fillcolor=gold,label="Provides\nfilesystem\ncontent"]; - Resource [label="Resource\n(Pager)"]; - - Resource_note -> Resource [dir=none,style=dotted]; - } - - subgraph { - rank=same; - - Provider_note [shape=note,style=filled,fillcolor=gold,label="Represents\nopen file"]; - Provider; - - Provider_note -> Provider [dir=none,style=dotted]; - } - - subgraph { - rank=same; - - PageMapper_note [shape=note,style=filled,fillcolor=gold,label="Provides\npopulated\nfile pages"]; - PageMapper; - - PageMapper_note -> PageMapper [dir=none,style=dotted]; - } - - ProviderRegistry [shape=record,label=" ProviderRegistry | ... | { file-n | provider-n } | ... "]; - - subgraph { - rank=same; - - FileOpening_note [shape=note,style=filled,fillcolor=gold,label="Exposes\nfilesystem\nfunctionality"]; - FileOpening; - - FileOpening_note -> FileOpening [dir=none,style=dotted]; - } - - subgraph { - rank=same; - - Accessor_note [shape=note,style=filled,fillcolor=gold,label="Populates\nfile pages"]; - Accessor; - Accessor_note -> Accessor [dir=none,style=dotted]; - } - - /* Opening a file. */ - - Opener -> ResourceRegistry -> Resource; - ResourceRegistry -> FileOpening; - - Provider -> PageMapper; - FileOpening -> Accessor; - - /* Closing a file. */ - - Resource -> Provider -> ProviderRegistry:head; - - /* Open file management. */ - - ResourceRegistry -> ProviderRegistry:head; -} -}}} - -######## - -An `Opener` requests a `Resource` from a `ResourceRegistry`, each `Resource` -acting as a [[ServerLibrary#Pager|`Pager`]] and providing the actual access -mechanism to file content for a particular program. Since many programs may -access the same file simultaneously, a `Provider` object represents a file -opened in the system, retaining a `PageMapper` that coordinates the collective -access to the file (see the [[Paging|paging documentation]] for more -information). - -A `ProviderRegistry` maintains the record of opened files, yielding a new -`Provider` for an unopened file or an existing `Provider` for a file that is -already open. The `ProviderRegistry` monitors the usage of files, discarding -any `Provider` no longer in use. - -== Opening Files == - -Opening a file involves the identification of the filesystem object involved, -the acquisition of a `Provider` representing the file, and the creation of a -`Resource` to deliver file content to the requesting program. - -######## A graph showing the opening mechanism for an already-open file - -{{{#!graphviz -#format svg -#transform notugly -digraph opening_open { - node [fontsize="12.0",fontname="sans-serif",shape=box]; - edge [fontsize="12.0",fontname="sans-serif"]; - rankdir=LR; - - subgraph { - rank=same; - - Opener_note [shape=note,style=filled,fillcolor=gold,label="Exposes\nfile open\noperation"]; - Opener; - - Opener_note -> Opener [dir=none,style=dotted]; - } - - subgraph { - rank=same; - - ResourceRegistry_note [shape=note,style=filled,fillcolor=gold,label="Records\nopen file\nsessions"]; - ResourceRegistry; - - Resource_returned [label="Resource\n(Pager)"]; - Resource_returned_note [shape=note,style=filled,fillcolor=gold,label="Provides\nfilesystem\ncontent"]; - - ResourceRegistry_note -> ResourceRegistry [dir=none,style=dotted]; - Resource_returned -> Resource_returned_note [dir=none,style=dotted]; - } - - subgraph { - rank=same; - - Resource [label="Resource\n(Pager)"]; - - FileOpening_note [shape=note,style=filled,fillcolor=gold,label="Exposes\nfilesystem\nfunctionality"]; - FileOpening; - - FileOpening_note -> FileOpening [dir=none,style=dotted]; - } - - subgraph { - rank=max; - - ProviderRegistry_note [shape=note,style=filled,fillcolor=gold,label="Provides\nopen files"]; - ProviderRegistry; - - Provider; - Provider_note [shape=note,style=filled,fillcolor=gold,label="Represents\nopen file"]; - - ProviderRegistry_note -> ProviderRegistry [dir=none,style=dotted]; - Provider -> Provider_note [dir=none,style=dotted]; - } - - /* Obtaining a resource from the registry. */ - - Opener -> ResourceRegistry [label="get_resource"]; - ResourceRegistry -> Resource_returned [dir=none]; - Resource_returned -> Opener; - - /* Obtaining a provider. */ - - ResourceRegistry -> FileOpening [label="get_fileid"]; - ResourceRegistry -> ProviderRegistry [label="get(fileid)"]; - ProviderRegistry -> Provider; - - /* Obtaining the resource from the provider. */ - - ResourceRegistry -> Provider [label="make_resource"]; - Provider -> Resource [dir=none]; - Resource -> ResourceRegistry; -} -}}} - -######## - -Where a provider does not already exist, with the file not having been opened -already, some extra interactions occur: - -######## A graph showing opening mechanism details for an unopened file - -{{{#!graphviz -#format svg -#transform notugly -digraph opening_unopened { - node [fontsize="12.0",fontname="sans-serif",shape=box]; - edge [fontsize="12.0",fontname="sans-serif"]; - rankdir=LR; - - Opener; - - ResourceRegistry; - - subgraph { - rank=same; - - Provider_note [shape=note,style=filled,fillcolor=gold,label="Created\nand set in\nregistry"]; - Provider; - - Accessor; - PageMapper; - PageMapper_note [shape=note,style=filled,fillcolor=gold,label="Created\nfor provider"]; - - Provider_note -> Provider [dir=none,style=dotted]; - PageMapper -> PageMapper_note [dir=none,style=dotted]; - } - - subgraph { - rank=max; - - ProviderRegistry_note [shape=note,style=filled,fillcolor=gold,label="Records\nopen files"]; - ProviderRegistry; - FileOpening; - FileOpening_note [shape=note,style=filled,fillcolor=gold,label="Exposes\nfilesystem\nfunctionality"]; - - ProviderRegistry_note -> ProviderRegistry [dir=none,style=dotted]; - FileOpening -> FileOpening_note [dir=none,style=dotted]; - } - - Opener -> ResourceRegistry [dir=none,style=dashed]; - - /* Obtaining a new provider. */ - - ResourceRegistry -> FileOpening [label="make_accessor"]; - FileOpening -> Accessor [dir=none]; - Accessor -> PageMapper -> ResourceRegistry; - - ResourceRegistry -> Provider [dir=none]; - Provider -> ProviderRegistry [label="set(fileid)"]; -} -}}} - -######## - -== Notifications == - -Within the filesystem access architecture, users of files may act in ways that -may notify other users of the same file. To support such notifications, an -interface is provided for filesystem clients to subscribe and unsubscribe to -notifications. The notifications themselves occur when files are opened, -modified and closed. Pipes also generate notifications when a pipe reader -makes more space available for the writer. - -######## A graph showing subscription to notifications - -{{{#!graphviz -#format svg -#transform notugly -digraph notification_subscriptions { - node [fontsize="12.0",fontname="sans-serif",shape=box]; - edge [fontsize="12.0",fontname="sans-serif"]; - rankdir=LR; - - subgraph { - rank=same; - - Client1 [label="Client\nprogram"]; - Client2 [label="Client\nprogram"]; - } - - subgraph { - rank=same; - - Notifier1_note [shape=note,style=filled,fillcolor=gold,label="Created for\nnotifications"]; - Notifier1 [label="Notifier"]; - Notifier2 [label="Notifier"]; - - Notifier1_note -> Notifier1 -> Notifier2 [dir=none,style=dotted]; - } - - subgraph { - rank=same; - - Resource1 [label="Resource\n(Pager)"]; - Resource2 [label="Resource\n(Pager)"]; - } - - subgraph { - rank=same; - - Notifier1_subscribe_note [shape=note,style=filled,fillcolor=gold,label="Propagated to\nprovider"]; - Notifier1_subscribe [label="Notifier"]; - Notifier2_subscribe [label="Notifier"]; - - Notifier1_subscribe_note -> Notifier1_subscribe -> Notifier2_subscribe [dir=none,style=dotted]; - } - - subgraph { - rank=same; - - Provider_note [shape=note,style=filled,fillcolor=gold,label="Manages file\nsubscriptions"]; - Provider [label="Provider"]; - - Provider_note -> Provider [dir=none,style=dotted]; - } - - /* Subscribing. */ - - Client1 -> Notifier1 [dir=none]; - Notifier1 -> Resource1 [label="subscribe"]; - - Resource1 -> Notifier1_subscribe [dir=none]; - Notifier1_subscribe -> Provider [label="subscribe"]; - - Client2 -> Notifier2 [dir=none]; - Notifier2 -> Resource2 [label="subscribe"]; - - Resource2 -> Notifier2_subscribe [dir=none]; - Notifier2_subscribe -> Provider [label="subscribe"]; -} -}}} - -######## - -An example of a notification scenario is given below: - -######## A graph showing notification - -{{{#!graphviz -#format svg -#transform notugly -digraph notifications { - node [fontsize="12.0",fontname="sans-serif",shape=box]; - edge [fontsize="12.0",fontname="sans-serif"]; - rankdir=LR; - - subgraph { - rank=same; - - Client1 [label="Client\nprogram"]; - Client2 [label="Client\nprogram"]; - } - - subgraph { - rank=same; - - Notifier1_note [shape=note,style=filled,fillcolor=gold,label="Registered for\nnotifications"]; - Notifier1 [label="Notifier"]; - - Resource2 [label="Resource\n(Pager)"]; - Resource2_note [shape=note,style=filled,fillcolor=gold,label="Generates\nnotification"]; - - Notifier1_note -> Notifier1 [dir=none,style=dotted]; - Resource2 -> Resource2_note [dir=none,style=dotted]; - } - - subgraph { - rank=same; - - Provider_note [shape=note,style=filled,fillcolor=gold,label="Propagates\nnotifications"]; - Provider [label="Provider"]; - - Provider_note -> Provider [dir=none,style=dotted]; - } - - /* A notification scenario. */ - - Client2 -> Resource2 [label="resize"]; - Resource2 -> Provider [label="notify_others"]; - Provider -> Notifier1 [label="notify"]; - Client1 -> Notifier1 [label="wait"]; -} -}}} - -######## - -Notifications provide the basis for blocking reading and writing operations, -with pipe endpoints depending on such blocking for efficient use of pipes. The -interactions involved when transferring data through pipes are depicted below. - -######## A graph showing notifications employed by pipe endpoints - -{{{#!graphviz -#format svg -#transform notugly -digraph pipe_notifications { - node [fontsize="12.0",fontname="sans-serif",shape=box]; - edge [fontsize="12.0",fontname="sans-serif"]; - rankdir=LR; - - subgraph { - rank=min; - - Client1_note [shape=note,style=filled,fillcolor=gold,label="Fill pipe\nthen request\nmore space"]; - Client1 [label="Client\nprogram\n(writer)"]; - Client1_wait_note [shape=note,style=filled,fillcolor=gold,label="Waiting after\nfilling pipe"]; - Client1_wait [label="Client\nprogram\n(writer)"]; - - Client1_note -> Client1 [dir=none,style=dotted]; - Client1_wait_note -> Client1_wait [dir=none,style=dotted]; - - Client1 -> Client1_wait_note [dir=none,style=invis]; - } - - subgraph { - rank=max; - - Client2_note [shape=note,style=filled,fillcolor=gold,label="Waiting for\nmore content\nbefore reading"]; - Client2 [label="Client\nprogram\n(reader)"]; - Client2_read_note [shape=note,style=filled,fillcolor=gold,label="Empty pipe\nthen request\nmore content"]; - Client2_read [label="Client\nprogram\n(reader)"]; - - Client2_note -> Client2 [dir=none,style=dotted]; - Client2_read_note -> Client2_read [dir=none,style=dotted]; - } - - subgraph { - rank=same; - - Notifier1 [label="Notifier"]; - Resource1 [label="Resource\n(PipePager)"]; - } - - subgraph { - rank=same; - - Notifier2 [label="Notifier"]; - Resource2 [label="Resource\n(PipePager)"]; - } - - subgraph { - rank=same; - - PipePaging [label="Provider\n(PipePaging)"]; - PipePaging_space [label="Provider\n(PipePaging)"]; - } - - /* Making content available. */ - - Client1 -> Resource1 [label="next_region"]; - Resource1 -> PipePaging [label="add_region"]; - PipePaging -> Notifier2 [label="notify"]; - Client2 -> Notifier2 [label="wait"]; - - /* Making space available. */ - - Client2_read -> Resource2 [label="next_region"]; - Resource2 -> PipePaging_space [label="next_region"]; - PipePaging_space -> Notifier1 [label="notify"]; - Client1_wait -> Notifier1 [label="wait"]; -} -}}} - -######## - -== Closing Files == - -Files are closed when client programs release their references to the resource -capabilities used to access files. The mechanism by which this is done -involves the registration of an IRQ object that is bound to the same thread as -the one used by resources to service file access requests. This IRQ object is -associated with the IPC gate through which such requests occur, and the IRQ -object is configured to deliver an interrupt message when the final reference -to the IPC gate has been released. - -When a client program terminates, its references to capabilities should be -released, and this should cause a reference counter associated with the IPC -gate to decrement. Upon the loss of the final reference and the delivery of -the interrupt, the server framework will call a `close` method on the -`Resource` object concerned, this implementing the -[[ServerLibrary#Accountable|`Accountable`]] interface. - -######## A graph showing the closing mechanism - -{{{#!graphviz -#format svg -#transform notugly -digraph closing { - node [fontsize="12.0",fontname="sans-serif",shape=box]; - edge [fontsize="12.0",fontname="sans-serif"]; - rankdir=LR; - - Client [label="Client\nprogram"]; - - subgraph { - rank=same; - - Gate_note [shape=note,style=filled,fillcolor=gold,label="Actual\nendpoint"]; - Gate [label="IPC gate",shape="octagon"]; - IRQ [shape="triangle"]; - ResourceServer; - ResourceServer_note [shape=note,style=filled,fillcolor=gold,label="Handles\nrequests"]; - - Gate_note -> Gate [dir=none,style=dotted]; - ResourceServer -> ResourceServer_note [dir=none,style=dotted]; - } - - Resource [label="Resource\n(Pager)"]; - - Provider; - - ProviderRegistry; - - Client -> Gate [style=dashed,label="(release)"]; - Gate -> IRQ -> ResourceServer; - ResourceServer -> Resource [label="close"]; - Resource -> Provider [label="notify_others\nunsubscribe"]; - Resource -> ProviderRegistry [label="detach"]; -} -}}} - -######## - -As a consequence of closing a file, an `unsubscribe` operation performed on -the `Provider` should cause any `Notifier` objects associated with the -`Resource` object to be released. Meanwhile, the `ResourceServer` will discard -the `Resource` object before the server thread terminates. - -== Removing Files == - -Unix filesystem semantics typically allow a file to be "unlinked" while still -being accessed by a program, with accesses still being directed to the file, -but with the file being removed from a directory and potentially being -replaced by another file. To support this, a mechanism is provided to defer -any removal of an open file. - -######## A graph showing the removal mechanism - -{{{#!graphviz -#format svg -#transform notugly -digraph removing { - node [fontsize="12.0",fontname="sans-serif",shape=box]; - edge [fontsize="12.0",fontname="sans-serif"]; - rankdir=LR; - - subgraph { - rank=same; - - Client1_note [shape=note,style=filled,fillcolor=gold,label="Removing\nopen file"]; - Client1 [label="Client\nprogram"]; - Client2 [label="Client\nprogram"]; - Client2_note [shape=note,style=filled,fillcolor=gold,label="Closes\nopen file"]; - - Client1_note -> Client1 [dir=none,style=dotted]; - Client2 -> Client2_note [dir=none,style=dotted]; - - Client1 -> Client2 [dir=none,style=invis]; - } - - subgraph { - rank=same; - - Resource [label="Resource\n(Pager)"]; - Opener; - } - - subgraph { - rank=same; - - Provider1 [label="Provider"]; - Provider1_note [shape=note,style=filled,fillcolor=gold,label="Maintains\nremoval\nstate"]; - Provider2 [label="Provider"]; - - Provider1 -> Provider1_note -> Provider2 [dir=none,style=dotted]; - } - - ProviderRegistry1 [label="ProviderRegistry"]; - ProviderRegistry2 [label="ProviderRegistry"]; - - subgraph { - rank=same; - - FileOpening; - Accessor_note [shape=note,style=filled,fillcolor=gold,label="Performing\nfilesystem\noperations"]; - Accessor; - - FileOpening -> Accessor_note -> Accessor [dir=none,style=dotted]; - } - - /* Removing the file while it remains open. */ - - Client1 -> Opener [label="remove\n(via context)"]; - Opener -> ResourceRegistry [label="remove_provider"]; - ResourceRegistry -> FileOpening [label="get_fileid\nunlink_object"]; - ResourceRegistry -> ProviderRegistry1 [label="get(fileid)"]; - ResourceRegistry -> Provider1 [label="remove_pending"]; - - /* File closure and deferred removal. */ - - Client2 -> Resource [label="close"]; - Resource -> Provider2 [label="notify_others\nunsubscribe"]; - Resource -> ProviderRegistry2 [label="detach"]; - ProviderRegistry2 -> Provider2 [label="remove"]; - Provider2 -> Accessor [label="remove"]; -} -}}} - -######## diff -r 8306354f755b -r f7c8fe9d968f docs/wiki/Filesystem_Access --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/docs/wiki/Filesystem_Access Fri Aug 12 16:41:06 2022 +0200 @@ -0,0 +1,611 @@ += Filesystem Access = + +Within the [[ServerLibrary|filesystem server library]], a number of different +abstractions and mechanisms are employed to provide access to filesystem +objects. An overview of these abstractions is presented below. + +######## A graph showing the relationships between filesystem access +######## components + +{{{#!graphviz +#format svg +#transform notugly +digraph components { + node [fontsize="12.0",fontname="sans-serif",shape=box]; + edge [fontsize="12.0",fontname="sans-serif"]; + rankdir=LR; + + subgraph { + rank=same; + + Opener_note [shape=note,style=filled,fillcolor=gold,label="Exposes\nfile open\noperation"]; + Opener; + + Opener_note -> Opener [dir=none,style=dotted]; + } + + subgraph { + rank=same; + + ResourceRegistry_note [shape=note,style=filled,fillcolor=gold,label="Records\nopen file\nsessions"]; + ResourceRegistry; + + ResourceRegistry_note -> ResourceRegistry [dir=none,style=dotted]; + } + + subgraph { + rank=same; + + Resource_note [shape=note,style=filled,fillcolor=gold,label="Provides\nfilesystem\ncontent"]; + Resource [label="Resource\n(Pager)"]; + + Resource_note -> Resource [dir=none,style=dotted]; + } + + subgraph { + rank=same; + + Provider_note [shape=note,style=filled,fillcolor=gold,label="Represents\nopen file"]; + Provider; + + Provider_note -> Provider [dir=none,style=dotted]; + } + + subgraph { + rank=same; + + PageMapper_note [shape=note,style=filled,fillcolor=gold,label="Provides\npopulated\nfile pages"]; + PageMapper; + + PageMapper_note -> PageMapper [dir=none,style=dotted]; + } + + ProviderRegistry [shape=record,label=" ProviderRegistry | ... | { file-n | provider-n } | ... "]; + + subgraph { + rank=same; + + FileOpening_note [shape=note,style=filled,fillcolor=gold,label="Exposes\nfilesystem\nfunctionality"]; + FileOpening; + + FileOpening_note -> FileOpening [dir=none,style=dotted]; + } + + subgraph { + rank=same; + + Accessor_note [shape=note,style=filled,fillcolor=gold,label="Populates\nfile pages"]; + Accessor; + Accessor_note -> Accessor [dir=none,style=dotted]; + } + + /* Opening a file. */ + + Opener -> ResourceRegistry -> Resource; + ResourceRegistry -> FileOpening; + + Provider -> PageMapper; + FileOpening -> Accessor; + + /* Closing a file. */ + + Resource -> Provider -> ProviderRegistry:head; + + /* Open file management. */ + + ResourceRegistry -> ProviderRegistry:head; +} +}}} + +######## + +An `Opener` requests a `Resource` from a `ResourceRegistry`, each `Resource` +acting as a [[ServerLibrary#Pager|`Pager`]] and providing the actual access +mechanism to file content for a particular program. Since many programs may +access the same file simultaneously, a `Provider` object represents a file +opened in the system, retaining a `PageMapper` that coordinates the collective +access to the file (see the [[Paging|paging documentation]] for more +information). + +A `ProviderRegistry` maintains the record of opened files, yielding a new +`Provider` for an unopened file or an existing `Provider` for a file that is +already open. The `ProviderRegistry` monitors the usage of files, discarding +any `Provider` no longer in use. + +== Opening Files == + +Opening a file involves the identification of the filesystem object involved, +the acquisition of a `Provider` representing the file, and the creation of a +`Resource` to deliver file content to the requesting program. + +######## A graph showing the opening mechanism for an already-open file + +{{{#!graphviz +#format svg +#transform notugly +digraph opening_open { + node [fontsize="12.0",fontname="sans-serif",shape=box]; + edge [fontsize="12.0",fontname="sans-serif"]; + rankdir=LR; + + subgraph { + rank=same; + + Opener_note [shape=note,style=filled,fillcolor=gold,label="Exposes\nfile open\noperation"]; + Opener; + + Opener_note -> Opener [dir=none,style=dotted]; + } + + subgraph { + rank=same; + + ResourceRegistry_note [shape=note,style=filled,fillcolor=gold,label="Records\nopen file\nsessions"]; + ResourceRegistry; + + Resource_returned [label="Resource\n(Pager)"]; + Resource_returned_note [shape=note,style=filled,fillcolor=gold,label="Provides\nfilesystem\ncontent"]; + + ResourceRegistry_note -> ResourceRegistry [dir=none,style=dotted]; + Resource_returned -> Resource_returned_note [dir=none,style=dotted]; + } + + subgraph { + rank=same; + + Resource [label="Resource\n(Pager)"]; + + FileOpening_note [shape=note,style=filled,fillcolor=gold,label="Exposes\nfilesystem\nfunctionality"]; + FileOpening; + + FileOpening_note -> FileOpening [dir=none,style=dotted]; + } + + subgraph { + rank=max; + + ProviderRegistry_note [shape=note,style=filled,fillcolor=gold,label="Provides\nopen files"]; + ProviderRegistry; + + Provider; + Provider_note [shape=note,style=filled,fillcolor=gold,label="Represents\nopen file"]; + + ProviderRegistry_note -> ProviderRegistry [dir=none,style=dotted]; + Provider -> Provider_note [dir=none,style=dotted]; + } + + /* Obtaining a resource from the registry. */ + + Opener -> ResourceRegistry [label="get_resource"]; + ResourceRegistry -> Resource_returned [dir=none]; + Resource_returned -> Opener; + + /* Obtaining a provider. */ + + ResourceRegistry -> FileOpening [label="get_fileid"]; + ResourceRegistry -> ProviderRegistry [label="get(fileid)"]; + ProviderRegistry -> Provider; + + /* Obtaining the resource from the provider. */ + + ResourceRegistry -> Provider [label="make_resource"]; + Provider -> Resource [dir=none]; + Resource -> ResourceRegistry; +} +}}} + +######## + +Where a provider does not already exist, with the file not having been opened +already, some extra interactions occur: + +######## A graph showing opening mechanism details for an unopened file + +{{{#!graphviz +#format svg +#transform notugly +digraph opening_unopened { + node [fontsize="12.0",fontname="sans-serif",shape=box]; + edge [fontsize="12.0",fontname="sans-serif"]; + rankdir=LR; + + Opener; + + ResourceRegistry; + + subgraph { + rank=same; + + Provider_note [shape=note,style=filled,fillcolor=gold,label="Created\nand set in\nregistry"]; + Provider; + + Accessor; + PageMapper; + PageMapper_note [shape=note,style=filled,fillcolor=gold,label="Created\nfor provider"]; + + Provider_note -> Provider [dir=none,style=dotted]; + PageMapper -> PageMapper_note [dir=none,style=dotted]; + } + + subgraph { + rank=max; + + ProviderRegistry_note [shape=note,style=filled,fillcolor=gold,label="Records\nopen files"]; + ProviderRegistry; + FileOpening; + FileOpening_note [shape=note,style=filled,fillcolor=gold,label="Exposes\nfilesystem\nfunctionality"]; + + ProviderRegistry_note -> ProviderRegistry [dir=none,style=dotted]; + FileOpening -> FileOpening_note [dir=none,style=dotted]; + } + + Opener -> ResourceRegistry [dir=none,style=dashed]; + + /* Obtaining a new provider. */ + + ResourceRegistry -> FileOpening [label="make_accessor"]; + FileOpening -> Accessor [dir=none]; + Accessor -> PageMapper -> ResourceRegistry; + + ResourceRegistry -> Provider [dir=none]; + Provider -> ProviderRegistry [label="set(fileid)"]; +} +}}} + +######## + +== Notifications == + +Within the filesystem access architecture, users of files may act in ways that +may notify other users of the same file. To support such notifications, an +interface is provided for filesystem clients to subscribe and unsubscribe to +notifications. The notifications themselves occur when files are opened, +modified and closed. Pipes also generate notifications when a pipe reader +makes more space available for the writer. + +######## A graph showing subscription to notifications + +{{{#!graphviz +#format svg +#transform notugly +digraph notification_subscriptions { + node [fontsize="12.0",fontname="sans-serif",shape=box]; + edge [fontsize="12.0",fontname="sans-serif"]; + rankdir=LR; + + subgraph { + rank=same; + + Client1 [label="Client\nprogram"]; + Client2 [label="Client\nprogram"]; + } + + subgraph { + rank=same; + + Notifier1_note [shape=note,style=filled,fillcolor=gold,label="Created for\nnotifications"]; + Notifier1 [label="Notifier"]; + Notifier2 [label="Notifier"]; + + Notifier1_note -> Notifier1 -> Notifier2 [dir=none,style=dotted]; + } + + subgraph { + rank=same; + + Resource1 [label="Resource\n(Pager)"]; + Resource2 [label="Resource\n(Pager)"]; + } + + subgraph { + rank=same; + + Notifier1_subscribe_note [shape=note,style=filled,fillcolor=gold,label="Propagated to\nprovider"]; + Notifier1_subscribe [label="Notifier"]; + Notifier2_subscribe [label="Notifier"]; + + Notifier1_subscribe_note -> Notifier1_subscribe -> Notifier2_subscribe [dir=none,style=dotted]; + } + + subgraph { + rank=same; + + Provider_note [shape=note,style=filled,fillcolor=gold,label="Manages file\nsubscriptions"]; + Provider [label="Provider"]; + + Provider_note -> Provider [dir=none,style=dotted]; + } + + /* Subscribing. */ + + Client1 -> Notifier1 [dir=none]; + Notifier1 -> Resource1 [label="subscribe"]; + + Resource1 -> Notifier1_subscribe [dir=none]; + Notifier1_subscribe -> Provider [label="subscribe"]; + + Client2 -> Notifier2 [dir=none]; + Notifier2 -> Resource2 [label="subscribe"]; + + Resource2 -> Notifier2_subscribe [dir=none]; + Notifier2_subscribe -> Provider [label="subscribe"]; +} +}}} + +######## + +An example of a notification scenario is given below: + +######## A graph showing notification + +{{{#!graphviz +#format svg +#transform notugly +digraph notifications { + node [fontsize="12.0",fontname="sans-serif",shape=box]; + edge [fontsize="12.0",fontname="sans-serif"]; + rankdir=LR; + + subgraph { + rank=same; + + Client1 [label="Client\nprogram"]; + Client2 [label="Client\nprogram"]; + } + + subgraph { + rank=same; + + Notifier1_note [shape=note,style=filled,fillcolor=gold,label="Registered for\nnotifications"]; + Notifier1 [label="Notifier"]; + + Resource2 [label="Resource\n(Pager)"]; + Resource2_note [shape=note,style=filled,fillcolor=gold,label="Generates\nnotification"]; + + Notifier1_note -> Notifier1 [dir=none,style=dotted]; + Resource2 -> Resource2_note [dir=none,style=dotted]; + } + + subgraph { + rank=same; + + Provider_note [shape=note,style=filled,fillcolor=gold,label="Propagates\nnotifications"]; + Provider [label="Provider"]; + + Provider_note -> Provider [dir=none,style=dotted]; + } + + /* A notification scenario. */ + + Client2 -> Resource2 [label="resize"]; + Resource2 -> Provider [label="notify_others"]; + Provider -> Notifier1 [label="notify"]; + Client1 -> Notifier1 [label="wait"]; +} +}}} + +######## + +Notifications provide the basis for blocking reading and writing operations, +with pipe endpoints depending on such blocking for efficient use of pipes. The +interactions involved when transferring data through pipes are depicted below. + +######## A graph showing notifications employed by pipe endpoints + +{{{#!graphviz +#format svg +#transform notugly +digraph pipe_notifications { + node [fontsize="12.0",fontname="sans-serif",shape=box]; + edge [fontsize="12.0",fontname="sans-serif"]; + rankdir=LR; + + subgraph { + rank=min; + + Client1_note [shape=note,style=filled,fillcolor=gold,label="Fill pipe\nthen request\nmore space"]; + Client1 [label="Client\nprogram\n(writer)"]; + Client1_wait_note [shape=note,style=filled,fillcolor=gold,label="Waiting after\nfilling pipe"]; + Client1_wait [label="Client\nprogram\n(writer)"]; + + Client1_note -> Client1 [dir=none,style=dotted]; + Client1_wait_note -> Client1_wait [dir=none,style=dotted]; + + Client1 -> Client1_wait_note [dir=none,style=invis]; + } + + subgraph { + rank=max; + + Client2_note [shape=note,style=filled,fillcolor=gold,label="Waiting for\nmore content\nbefore reading"]; + Client2 [label="Client\nprogram\n(reader)"]; + Client2_read_note [shape=note,style=filled,fillcolor=gold,label="Empty pipe\nthen request\nmore content"]; + Client2_read [label="Client\nprogram\n(reader)"]; + + Client2_note -> Client2 [dir=none,style=dotted]; + Client2_read_note -> Client2_read [dir=none,style=dotted]; + } + + subgraph { + rank=same; + + Notifier1 [label="Notifier"]; + Resource1 [label="Resource\n(PipePager)"]; + } + + subgraph { + rank=same; + + Notifier2 [label="Notifier"]; + Resource2 [label="Resource\n(PipePager)"]; + } + + subgraph { + rank=same; + + PipePaging [label="Provider\n(PipePaging)"]; + PipePaging_space [label="Provider\n(PipePaging)"]; + } + + /* Making content available. */ + + Client1 -> Resource1 [label="next_region"]; + Resource1 -> PipePaging [label="add_region"]; + PipePaging -> Notifier2 [label="notify"]; + Client2 -> Notifier2 [label="wait"]; + + /* Making space available. */ + + Client2_read -> Resource2 [label="next_region"]; + Resource2 -> PipePaging_space [label="next_region"]; + PipePaging_space -> Notifier1 [label="notify"]; + Client1_wait -> Notifier1 [label="wait"]; +} +}}} + +######## + +== Closing Files == + +Files are closed when client programs release their references to the resource +capabilities used to access files. The mechanism by which this is done +involves the registration of an IRQ object that is bound to the same thread as +the one used by resources to service file access requests. This IRQ object is +associated with the IPC gate through which such requests occur, and the IRQ +object is configured to deliver an interrupt message when the final reference +to the IPC gate has been released. + +When a client program terminates, its references to capabilities should be +released, and this should cause a reference counter associated with the IPC +gate to decrement. Upon the loss of the final reference and the delivery of +the interrupt, the server framework will call a `close` method on the +`Resource` object concerned, this implementing the +[[ServerLibrary#Accountable|`Accountable`]] interface. + +######## A graph showing the closing mechanism + +{{{#!graphviz +#format svg +#transform notugly +digraph closing { + node [fontsize="12.0",fontname="sans-serif",shape=box]; + edge [fontsize="12.0",fontname="sans-serif"]; + rankdir=LR; + + Client [label="Client\nprogram"]; + + subgraph { + rank=same; + + Gate_note [shape=note,style=filled,fillcolor=gold,label="Actual\nendpoint"]; + Gate [label="IPC gate",shape="octagon"]; + IRQ [shape="triangle"]; + ResourceServer; + ResourceServer_note [shape=note,style=filled,fillcolor=gold,label="Handles\nrequests"]; + + Gate_note -> Gate [dir=none,style=dotted]; + ResourceServer -> ResourceServer_note [dir=none,style=dotted]; + } + + Resource [label="Resource\n(Pager)"]; + + Provider; + + ProviderRegistry; + + Client -> Gate [style=dashed,label="(release)"]; + Gate -> IRQ -> ResourceServer; + ResourceServer -> Resource [label="close"]; + Resource -> Provider [label="notify_others\nunsubscribe"]; + Resource -> ProviderRegistry [label="detach"]; +} +}}} + +######## + +As a consequence of closing a file, an `unsubscribe` operation performed on +the `Provider` should cause any `Notifier` objects associated with the +`Resource` object to be released. Meanwhile, the `ResourceServer` will discard +the `Resource` object before the server thread terminates. + +== Removing Files == + +Unix filesystem semantics typically allow a file to be "unlinked" while still +being accessed by a program, with accesses still being directed to the file, +but with the file being removed from a directory and potentially being +replaced by another file. To support this, a mechanism is provided to defer +any removal of an open file. + +######## A graph showing the removal mechanism + +{{{#!graphviz +#format svg +#transform notugly +digraph removing { + node [fontsize="12.0",fontname="sans-serif",shape=box]; + edge [fontsize="12.0",fontname="sans-serif"]; + rankdir=LR; + + subgraph { + rank=same; + + Client1_note [shape=note,style=filled,fillcolor=gold,label="Removing\nopen file"]; + Client1 [label="Client\nprogram"]; + Client2 [label="Client\nprogram"]; + Client2_note [shape=note,style=filled,fillcolor=gold,label="Closes\nopen file"]; + + Client1_note -> Client1 [dir=none,style=dotted]; + Client2 -> Client2_note [dir=none,style=dotted]; + + Client1 -> Client2 [dir=none,style=invis]; + } + + subgraph { + rank=same; + + Resource [label="Resource\n(Pager)"]; + Opener; + } + + subgraph { + rank=same; + + Provider1 [label="Provider"]; + Provider1_note [shape=note,style=filled,fillcolor=gold,label="Maintains\nremoval\nstate"]; + Provider2 [label="Provider"]; + + Provider1 -> Provider1_note -> Provider2 [dir=none,style=dotted]; + } + + ProviderRegistry1 [label="ProviderRegistry"]; + ProviderRegistry2 [label="ProviderRegistry"]; + + subgraph { + rank=same; + + FileOpening; + Accessor_note [shape=note,style=filled,fillcolor=gold,label="Performing\nfilesystem\noperations"]; + Accessor; + + FileOpening -> Accessor_note -> Accessor [dir=none,style=dotted]; + } + + /* Removing the file while it remains open. */ + + Client1 -> Opener [label="remove\n(via context)"]; + Opener -> ResourceRegistry [label="remove_provider"]; + ResourceRegistry -> FileOpening [label="get_fileid\nunlink_object"]; + ResourceRegistry -> ProviderRegistry1 [label="get(fileid)"]; + ResourceRegistry -> Provider1 [label="remove_pending"]; + + /* File closure and deferred removal. */ + + Client2 -> Resource [label="close"]; + Resource -> Provider2 [label="notify_others\nunsubscribe"]; + Resource -> ProviderRegistry2 [label="detach"]; + ProviderRegistry2 -> Provider2 [label="remove"]; + Provider2 -> Accessor [label="remove"]; +} +}}} + +######## diff -r 8306354f755b -r f7c8fe9d968f docs/wiki/Filesystems --- a/docs/wiki/Filesystems Wed Aug 10 23:58:38 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,19 +0,0 @@ -= Filesystems = - -This distribution aims to provide components and libraries to implement and -deliver filesystem access in the L4 Runtime Environment. - -== Topics == - - * [[ClientLibrary|Client Library]] - convenience functions and structures to - access filesystem objects - * [[Components]] - server objects exposed at the system level that support - filesystem access - * [[FilesystemAccess|Filesystem Access]] - mechanisms within filesystem - servers to manage filesystem resources and content - * [[Paging]] - the mechanism by which filesystem content is provided for use - by client programs - * [[ProgramLoading|Program Loading]] - the mechanism by which programs are loaded - * [[ServerLibrary|Server Library]] - abstractions to expose and manage access - to filesystem objects - * [[Users]] diff -r 8306354f755b -r f7c8fe9d968f docs/wiki/ProgramLoading --- a/docs/wiki/ProgramLoading Wed Aug 10 23:58:38 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,236 +0,0 @@ -= Program Loading = - -The provision of [[Paging|paging]] of file content leads to the possibility of -demand paging for programs, enabling them to be loaded into memory dynamically -and to have only the active portions of those programs resident. To achieve -this, programs must be appropriately initialised in new tasks, with a page -fault handler configured to provide program file content whenever a region of -the program payload is encountered that is not currently resident in memory. - -== Internal Page Fault Handlers == - -When satisfying page faults for a task, one approach involves situating the -page fault handler within the task itself, this managing the available memory -regions and employing receive windows when requesting memory pages. - -The general arrangement involving such internal page fault handlers for a -program in a task is as follows: - -######## A graph showing the internal paging mechanism - -{{{#!graphviz -#format svg -#transform notugly -digraph internal_paging { - node [fontsize="12.0",fontname="sans-serif",shape=box]; - edge [fontsize="12.0",fontname="sans-serif"]; - rankdir=LR; - - TaskMemory [shape=record,label="Task Memory | stack | ... | data | ... | code"]; - - subgraph { - rank=same; - - InternalPager; - InternalPager_note [shape=note,style=filled,fillcolor=gold,label="Resides in\nsame task and\ndefines scope of\nfault resolution"]; - - InternalPager -> InternalPager_note [dir=none,style=dotted]; - } - - subgraph { - rank=same; - - Regions [shape=record,label="Regions | - { stack | stack-dataspace } | - { data |
data-dataspace } | - { code | code-dataspace } |..."]; - - ReceiveFlexpage [shape=note,label="Flexpage\n(receive window)"]; - - Flexpage [shape=note]; - Flexpage_note [shape=note,style=filled,fillcolor=gold,label="Satisfies\nmemory\naccess"]; - - Flexpage -> Flexpage_note [dir=none,style=dotted]; - } - - subgraph { - rank=same; - - ResourceD [label="Resource\n(Pager)"]; - ResourceD_note [shape=note,style=filled,fillcolor=gold,label="Provides access\nto file content"]; - - ResourceD -> ResourceD_note [dir=none,style=dotted]; - } - - ProgramFile [shape=record,label="Program File | ... | data | code | ..."]; - - /* Page fault handling. */ - - TaskMemory:d -> InternalPager [label="page fault"]; - - InternalPager -> Regions:d [label="find region"]; - - Regions:dd -> ResourceD [style=dashed]; - - InternalPager -> ReceiveFlexpage [dir=none]; - ReceiveFlexpage -> ResourceD [label="map"]; - - ResourceD -> ProgramFile:d [style=dashed]; - - ResourceD -> Flexpage [dir=none]; - Flexpage -> InternalPager; -} -}}} - -######## - -== External Page Fault Handlers == - -Another approach that may be used to support an internal page fault handler -deployed in a task is to employ an external page fault handler in the creating -task. When a page fault occurs, the external handler ensures that the -appropriate content has been brought into its own memory space. It then -returns a flexpage from the handler routine to resolve the fault. - -######## A graph showing the external paging mechanism - -{{{#!graphviz -#format svg -#transform notugly -digraph external_paging { - node [fontsize="12.0",fontname="sans-serif",shape=box]; - edge [fontsize="12.0",fontname="sans-serif"]; - rankdir=LR; - - TaskMemory [shape=record,label="Task Memory | stack | ... | data | ... | code"]; - - subgraph { - rank=same; - - ExternalPager_note [shape=note,style=filled,fillcolor=gold,label="Resides in\nseparate task"]; - ExternalPager; - - ExternalPager_note -> ExternalPager [dir=none,style=dotted]; - - MappedFlexpage [shape=note,label="Flexpage\n(positioned)"]; - MappedFlexpage_note [shape=note,style=filled,fillcolor=gold,label="Satisfies\nmemory\naccess"]; - - MappedFlexpage -> MappedFlexpage_note [dir=none,style=dotted]; - } - - subgraph { - rank=same; - - Regions [shape=record,label="Regions | - { stack | stack-dataspace } | - { data |
data-dataspace } | - { code | code-dataspace } |..."]; - - L4Re [shape=ellipse,label="L4Re paging\nfunctionality"]; - L4Re_note [shape=note,style=filled,fillcolor=gold,label="Supports normal\naccess to file content"]; - - L4Re -> L4Re_note [dir=none,style=dotted]; - - Flexpage [shape=note]; - } - - subgraph { - rank=same; - - ResourceD [label="Resource\n(Pager)"]; - ResourceD_note [shape=note,style=filled,fillcolor=gold,label="Provides access\nto file content"]; - - ResourceD -> ResourceD_note [dir=none,style=dotted]; - } - - ProgramFile [shape=record,label="Program File | ... | data | code | ..."]; - - /* Page fault handling. */ - - TaskMemory:d -> ExternalPager [label="page fault"]; - - ExternalPager -> Regions:d [label="find region"]; - - Regions:dd -> ResourceD [style=dashed]; - - ExternalPager -> L4Re; - L4Re -> ResourceD [label="map"]; - - ResourceD -> ProgramFile:d [style=dashed]; - - ResourceD -> Flexpage [dir=none]; - Flexpage -> ExternalPager; - - ExternalPager -> MappedFlexpage [dir=none]; - MappedFlexpage -> TaskMemory:d; -} -}}} - -######## - -== Configuring Programs == - -To provide an internal page fault handler alongside an actual program to be -run, the following arrangement is used: - -######## A graph showing the configuration arrangement - -{{{#!graphviz -#format svg -#transform notugly -digraph program_configuration { - node [fontsize="12.0",fontname="sans-serif",shape=box]; - edge [fontsize="12.0",fontname="sans-serif"]; - rankdir=LR; - - subgraph { - rank=min; - - CreatingTask_note [shape=note,style=filled,fillcolor=gold,label="Responsible for\ncreating the\nnew task"]; - CreatingTask [label="Creating task"]; - - CreatingTask_note -> CreatingTask [dir=none,style=dotted]; - } - - subgraph { - rank=max; - - IPCGate_note [shape=note,style=filled,fillcolor=gold,label="Created for sharing\nbetween the tasks"]; - IPCGate [shape=octagon,label="IPC gate"]; - - IPCGate_note -> IPCGate [dir=none,style=dotted]; - } - - InitCaps [shape=record,label=" Initial capabilities | { \"server\" | capability }"]; - - subgraph { - rank=same; - - InternalPager; - InternalPager_note [shape=note,style=filled,fillcolor=gold,label="Starts and binds\nto IPC gate"]; - - InternalPager -> InternalPager_note [dir=none,style=dotted]; - - Program; - Program_note [shape=note,style=filled,fillcolor=gold,label="Starts and references\npager via IPC gate"]; - - Program -> Program_note [dir=none,style=dotted]; - } - - /* Create and transfer IPC gate for binding. */ - - CreatingTask -> IPCGate [label="create"]; - CreatingTask -> InitCaps:head [label="define"]; - InitCaps:c -> IPCGate; - - /* Thread initiation. */ - - CreatingTask -> InternalPager [label="start"]; - InternalPager -> InitCaps:s [label="bind"]; - - CreatingTask -> Program [label="start"]; - Program -> IPCGate -> InternalPager [style=dashed]; -} -}}} - -######## diff -r 8306354f755b -r f7c8fe9d968f docs/wiki/Program_Loading --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/docs/wiki/Program_Loading Fri Aug 12 16:41:06 2022 +0200 @@ -0,0 +1,236 @@ += Program Loading = + +The provision of [[Paging|paging]] of file content leads to the possibility of +demand paging for programs, enabling them to be loaded into memory dynamically +and to have only the active portions of those programs resident. To achieve +this, programs must be appropriately initialised in new tasks, with a page +fault handler configured to provide program file content whenever a region of +the program payload is encountered that is not currently resident in memory. + +== Internal Page Fault Handlers == + +When satisfying page faults for a task, one approach involves situating the +page fault handler within the task itself, this managing the available memory +regions and employing receive windows when requesting memory pages. + +The general arrangement involving such internal page fault handlers for a +program in a task is as follows: + +######## A graph showing the internal paging mechanism + +{{{#!graphviz +#format svg +#transform notugly +digraph internal_paging { + node [fontsize="12.0",fontname="sans-serif",shape=box]; + edge [fontsize="12.0",fontname="sans-serif"]; + rankdir=LR; + + TaskMemory [shape=record,label="Task Memory | stack | ... | data | ... | code"]; + + subgraph { + rank=same; + + InternalPager; + InternalPager_note [shape=note,style=filled,fillcolor=gold,label="Resides in\nsame task and\ndefines scope of\nfault resolution"]; + + InternalPager -> InternalPager_note [dir=none,style=dotted]; + } + + subgraph { + rank=same; + + Regions [shape=record,label="Regions | + { stack | stack-dataspace } | + { data |
data-dataspace } | + { code | code-dataspace } |..."]; + + ReceiveFlexpage [shape=note,label="Flexpage\n(receive window)"]; + + Flexpage [shape=note]; + Flexpage_note [shape=note,style=filled,fillcolor=gold,label="Satisfies\nmemory\naccess"]; + + Flexpage -> Flexpage_note [dir=none,style=dotted]; + } + + subgraph { + rank=same; + + ResourceD [label="Resource\n(Pager)"]; + ResourceD_note [shape=note,style=filled,fillcolor=gold,label="Provides access\nto file content"]; + + ResourceD -> ResourceD_note [dir=none,style=dotted]; + } + + ProgramFile [shape=record,label="Program File | ... | data | code | ..."]; + + /* Page fault handling. */ + + TaskMemory:d -> InternalPager [label="page fault"]; + + InternalPager -> Regions:d [label="find region"]; + + Regions:dd -> ResourceD [style=dashed]; + + InternalPager -> ReceiveFlexpage [dir=none]; + ReceiveFlexpage -> ResourceD [label="map"]; + + ResourceD -> ProgramFile:d [style=dashed]; + + ResourceD -> Flexpage [dir=none]; + Flexpage -> InternalPager; +} +}}} + +######## + +== External Page Fault Handlers == + +Another approach that may be used to support an internal page fault handler +deployed in a task is to employ an external page fault handler in the creating +task. When a page fault occurs, the external handler ensures that the +appropriate content has been brought into its own memory space. It then +returns a flexpage from the handler routine to resolve the fault. + +######## A graph showing the external paging mechanism + +{{{#!graphviz +#format svg +#transform notugly +digraph external_paging { + node [fontsize="12.0",fontname="sans-serif",shape=box]; + edge [fontsize="12.0",fontname="sans-serif"]; + rankdir=LR; + + TaskMemory [shape=record,label="Task Memory | stack | ... | data | ... | code"]; + + subgraph { + rank=same; + + ExternalPager_note [shape=note,style=filled,fillcolor=gold,label="Resides in\nseparate task"]; + ExternalPager; + + ExternalPager_note -> ExternalPager [dir=none,style=dotted]; + + MappedFlexpage [shape=note,label="Flexpage\n(positioned)"]; + MappedFlexpage_note [shape=note,style=filled,fillcolor=gold,label="Satisfies\nmemory\naccess"]; + + MappedFlexpage -> MappedFlexpage_note [dir=none,style=dotted]; + } + + subgraph { + rank=same; + + Regions [shape=record,label="Regions | + { stack | stack-dataspace } | + { data |
data-dataspace } | + { code | code-dataspace } |..."]; + + L4Re [shape=ellipse,label="L4Re paging\nfunctionality"]; + L4Re_note [shape=note,style=filled,fillcolor=gold,label="Supports normal\naccess to file content"]; + + L4Re -> L4Re_note [dir=none,style=dotted]; + + Flexpage [shape=note]; + } + + subgraph { + rank=same; + + ResourceD [label="Resource\n(Pager)"]; + ResourceD_note [shape=note,style=filled,fillcolor=gold,label="Provides access\nto file content"]; + + ResourceD -> ResourceD_note [dir=none,style=dotted]; + } + + ProgramFile [shape=record,label="Program File | ... | data | code | ..."]; + + /* Page fault handling. */ + + TaskMemory:d -> ExternalPager [label="page fault"]; + + ExternalPager -> Regions:d [label="find region"]; + + Regions:dd -> ResourceD [style=dashed]; + + ExternalPager -> L4Re; + L4Re -> ResourceD [label="map"]; + + ResourceD -> ProgramFile:d [style=dashed]; + + ResourceD -> Flexpage [dir=none]; + Flexpage -> ExternalPager; + + ExternalPager -> MappedFlexpage [dir=none]; + MappedFlexpage -> TaskMemory:d; +} +}}} + +######## + +== Configuring Programs == + +To provide an internal page fault handler alongside an actual program to be +run, the following arrangement is used: + +######## A graph showing the configuration arrangement + +{{{#!graphviz +#format svg +#transform notugly +digraph program_configuration { + node [fontsize="12.0",fontname="sans-serif",shape=box]; + edge [fontsize="12.0",fontname="sans-serif"]; + rankdir=LR; + + subgraph { + rank=min; + + CreatingTask_note [shape=note,style=filled,fillcolor=gold,label="Responsible for\ncreating the\nnew task"]; + CreatingTask [label="Creating task"]; + + CreatingTask_note -> CreatingTask [dir=none,style=dotted]; + } + + subgraph { + rank=max; + + IPCGate_note [shape=note,style=filled,fillcolor=gold,label="Created for sharing\nbetween the tasks"]; + IPCGate [shape=octagon,label="IPC gate"]; + + IPCGate_note -> IPCGate [dir=none,style=dotted]; + } + + InitCaps [shape=record,label=" Initial capabilities | { \"server\" | capability }"]; + + subgraph { + rank=same; + + InternalPager; + InternalPager_note [shape=note,style=filled,fillcolor=gold,label="Starts and binds\nto IPC gate"]; + + InternalPager -> InternalPager_note [dir=none,style=dotted]; + + Program; + Program_note [shape=note,style=filled,fillcolor=gold,label="Starts and references\npager via IPC gate"]; + + Program -> Program_note [dir=none,style=dotted]; + } + + /* Create and transfer IPC gate for binding. */ + + CreatingTask -> IPCGate [label="create"]; + CreatingTask -> InitCaps:head [label="define"]; + InitCaps:c -> IPCGate; + + /* Thread initiation. */ + + CreatingTask -> InternalPager [label="start"]; + InternalPager -> InitCaps:s [label="bind"]; + + CreatingTask -> Program [label="start"]; + Program -> IPCGate -> InternalPager [style=dashed]; +} +}}} + +######## diff -r 8306354f755b -r f7c8fe9d968f docs/wiki/ServerLibrary --- a/docs/wiki/ServerLibrary Wed Aug 10 23:58:38 2022 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,245 +0,0 @@ -= Server Library = - -Within the filesystem server library, a number of different abstractions and -mechanisms are employed to provide access to filesystem objects. - -<> - -This document uses C-style interface syntax since the components operating -within the described mechanisms will themselves be described using such -syntax. - -== Accountable == - -This interface provides the following operations: - -{{{ -void attach(); -unsigned int detach(); -}}} - -Its purpose is to provide reference counting for components, with the `attach` -operation incrementing the number of users of a component, and with the -`detach` operation decrementing the number of users and returning the -resulting number of users. When components no longer have any attached users, -they may perform operations to tidy up after themselves and permit their -deallocation. - -== Accessors == - -Accessors provide the means of accessing filesystem object data and metadata. -Conceptually, files and directories are both exposed by accessors, although -the interfaces and mechanisms may differ between these types of objects. - -=== Directory Accessors === - -Currently, directory accessors provide support for traversing directory -listings, obtaining the relevant filesystem metadata using the underlying -filesystem access library. - -=== File Accessors === - -File content is accessed through an interface with the following operations: - -{{{ -void close(); -void fill(Flexpage *flexpage); -void flush(Flexpage *flexpage); -offset_t get_size(); -void set_size(offset_t size); -}}} - -The operations need to be supported with actual filesystem operations. For -example, ext2-based filesystems employ a specific abstraction which invokes -library functions provided by the `libext2fs` package. - -== Providers == - -Providers encapsulate the essential functionality for accessing filesystem -objects. Implementing the `Accountable` interface, they are shared by -resources and discarded when no resources are using them. - -The following operations are supported by providers: - -{{{ -ProviderRegistry *registry(); -long make_resource(offset_t *size, object_flags_t *object_flags, Resource **resource); -bool removal_pending(); -void remove(); -void remove_pending(bool remove); -}}} - -Providers are associated with filesystem objects in a registry which can be -obtained from each provider using the `registry` operation. - -Providers also support the creation of resources through which each user of a -provider exercises its use of that provider. The `make_resource` operation -performs the creation and returns size, flags and resource instance details. - -The removal of providers can be directed using the `remove_pending` and -`remove` operations. Where `remove_pending` has been called with a true value -as its parameter, the `removal_pending` operation will also return a true -value, and upon the provider being discarded, the `remove` operation will be -invoked. The `remove` operation performs the appropriate underlying operation -to remove the object being provided. - -Typically, removal of providers is managed by the provider registry when -resources are closed and detached from providers. - -######## A graph showing the removal mechanism - -{{{#!graphviz -#format svg -#transform notugly -digraph provider_removal { - node [fontsize="12.0",fontname="sans-serif",shape=box]; - edge [fontsize="12.0",fontname="sans-serif"]; - rankdir=LR; - - ResourceServer -> Resource [label="close"]; - Resource -> ProviderRegistry [label="detach"]; - ProviderRegistry -> Provider [label="remove"]; -} -}}} - -######## - -== Resources == - -Resources are objects accessed by clients that support a basic level of -accounting and management. - -The base interface of a resource is as follows: - -{{{ -void activate(); -void close(); -}}} - -Activation of a resource is an optional operation that performs any -initialisation before a resource is made available to its user. - -In practice, other operations are required to make resources useful. - -In some cases, resources provide the mechanism by which each user of a -filesystem object may access that object independently. They would then -effectively provide a session in which accesses can occur. - -=== Directory Resources === - -Directory resources primarily expose the contents of directories in the -filesystem to a user. They employ directory accessors which concern themselves -with the actual filesystem content. - -[[Components#Directories|Directory components]] are provided using directory -resources. - -<> -=== Pagers or File Resources === - -Pagers are resources that support dataspace access operations, thus allowing -the resources to expose filesystem content in mapped memory regions to a -particular user of the object providing the content. - -[[Components#Files|File components]] and [[Components#Pipes|pipe components]] -are provided using pagers. - -=== Filesystem Resources === - -Filesystem resources provide the entry point for access to a filesystem by -other components or programs. Since filesystems often enforce identity-based -access controls, a filesystem resource will typically support the -`open_for_user` operation in various forms, with the result of this operation -being the instantiation of an `OpenerResource` configured for the indicated -user identity. - -== Registries == - -The basic mechanism for obtaining a resource involves a registry, as -illustrated by the following diagram. - -######## A graph showing the use of a registry in obtaining resources - -{{{#!graphviz -#format svg -#transform notugly -digraph registry { - node [fontsize="12.0",fontname="sans-serif",shape=box]; - edge [fontsize="12.0",fontname="sans-serif"]; - rankdir=LR; - - subgraph { - node [label="OpenerContextResource"]; - rank=same; - - OpenerContextResource1 -> OpenerContextResource2 [dir=none,style=dotted]; - } - - subgraph { - node [label="OpenerResource"]; - rank=same; - - OpenerResource1 -> OpenerResource2 [dir=none,style=dotted]; - } - - subgraph { - rank=same; - - ResourceRegistry -> Resource; - } - - subgraph { - rank=same; - - ProviderRegistry -> Provider; - } - - OpenerContextResource1 -> OpenerResource1 [label="open"]; - OpenerResource1 -> ResourceRegistry [label="get_resource"]; - ResourceRegistry -> ProviderRegistry [label="get/set"]; - - Provider -> Resource -> OpenerResource2 -> OpenerContextResource2; -} -}}} - -######## - -The `ResourceRegistry` coordinates access to filesystem resources and, through -synchronisation, prevents conflicting operations from occurring concurrently. -For example, a removal operation on a file may not be allowed to occur while -an opening operation is in progress. - -To achieve this, a common lock is employed to serialise access, with any -underlying filesystem operations being initiated from the registry while the -lock is held. An object providing the `FileOpening` interface for a filesystem -provides such operations, and the following interaction pattern is thereby -employed: - -######## A graph showing the registry coordinating filesystem operations - -{{{#!graphviz -#format svg -#transform notugly -digraph registry_operations { - node [fontsize="12.0",fontname="sans-serif",shape=box]; - edge [fontsize="12.0",fontname="sans-serif"]; - rankdir=LR; - - OpenerContextResource -> OpenerResource -> ResourceRegistry -> FileOpening; -} -}}} - -######## - -Since the `ResourceRegistry` functionality is generic, it could be specialised -for each filesystem or be configured with an appropriate reference to a -`FileOpening` object. The `OpenerResource` would then be generic, invoking the -registry which would, in turn, invoke the opening object. - -However, the chosen approach is to permit `OpenerResource` objects to -implement the `FileOpening` interface for each filesystem, meaning that the -`ResourceRegistry` will end up being called by the opener and then invoking -the opener in return. This is slightly more convenient than the alternative -since the opener can be configured with a given user identity, and such -identity details will ultimately be employed when accessing the underlying -filesystem itself. diff -r 8306354f755b -r f7c8fe9d968f docs/wiki/Server_Library --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/docs/wiki/Server_Library Fri Aug 12 16:41:06 2022 +0200 @@ -0,0 +1,245 @@ += Server Library = + +Within the filesystem server library, a number of different abstractions and +mechanisms are employed to provide access to filesystem objects. + +<> + +This document uses C-style interface syntax since the components operating +within the described mechanisms will themselves be described using such +syntax. + +== Accountable == + +This interface provides the following operations: + +{{{ +void attach(); +unsigned int detach(); +}}} + +Its purpose is to provide reference counting for components, with the `attach` +operation incrementing the number of users of a component, and with the +`detach` operation decrementing the number of users and returning the +resulting number of users. When components no longer have any attached users, +they may perform operations to tidy up after themselves and permit their +deallocation. + +== Accessors == + +Accessors provide the means of accessing filesystem object data and metadata. +Conceptually, files and directories are both exposed by accessors, although +the interfaces and mechanisms may differ between these types of objects. + +=== Directory Accessors === + +Currently, directory accessors provide support for traversing directory +listings, obtaining the relevant filesystem metadata using the underlying +filesystem access library. + +=== File Accessors === + +File content is accessed through an interface with the following operations: + +{{{ +void close(); +void fill(Flexpage *flexpage); +void flush(Flexpage *flexpage); +offset_t get_size(); +void set_size(offset_t size); +}}} + +The operations need to be supported with actual filesystem operations. For +example, ext2-based filesystems employ a specific abstraction which invokes +library functions provided by the `libext2fs` package. + +== Providers == + +Providers encapsulate the essential functionality for accessing filesystem +objects. Implementing the `Accountable` interface, they are shared by +resources and discarded when no resources are using them. + +The following operations are supported by providers: + +{{{ +ProviderRegistry *registry(); +long make_resource(offset_t *size, object_flags_t *object_flags, Resource **resource); +bool removal_pending(); +void remove(); +void remove_pending(bool remove); +}}} + +Providers are associated with filesystem objects in a registry which can be +obtained from each provider using the `registry` operation. + +Providers also support the creation of resources through which each user of a +provider exercises its use of that provider. The `make_resource` operation +performs the creation and returns size, flags and resource instance details. + +The removal of providers can be directed using the `remove_pending` and +`remove` operations. Where `remove_pending` has been called with a true value +as its parameter, the `removal_pending` operation will also return a true +value, and upon the provider being discarded, the `remove` operation will be +invoked. The `remove` operation performs the appropriate underlying operation +to remove the object being provided. + +Typically, removal of providers is managed by the provider registry when +resources are closed and detached from providers. + +######## A graph showing the removal mechanism + +{{{#!graphviz +#format svg +#transform notugly +digraph provider_removal { + node [fontsize="12.0",fontname="sans-serif",shape=box]; + edge [fontsize="12.0",fontname="sans-serif"]; + rankdir=LR; + + ResourceServer -> Resource [label="close"]; + Resource -> ProviderRegistry [label="detach"]; + ProviderRegistry -> Provider [label="remove"]; +} +}}} + +######## + +== Resources == + +Resources are objects accessed by clients that support a basic level of +accounting and management. + +The base interface of a resource is as follows: + +{{{ +void activate(); +void close(); +}}} + +Activation of a resource is an optional operation that performs any +initialisation before a resource is made available to its user. + +In practice, other operations are required to make resources useful. + +In some cases, resources provide the mechanism by which each user of a +filesystem object may access that object independently. They would then +effectively provide a session in which accesses can occur. + +=== Directory Resources === + +Directory resources primarily expose the contents of directories in the +filesystem to a user. They employ directory accessors which concern themselves +with the actual filesystem content. + +[[Components#Directories|Directory components]] are provided using directory +resources. + +<> +=== Pagers or File Resources === + +Pagers are resources that support dataspace access operations, thus allowing +the resources to expose filesystem content in mapped memory regions to a +particular user of the object providing the content. + +[[Components#Files|File components]] and [[Components#Pipes|pipe components]] +are provided using pagers. + +=== Filesystem Resources === + +Filesystem resources provide the entry point for access to a filesystem by +other components or programs. Since filesystems often enforce identity-based +access controls, a filesystem resource will typically support the +`open_for_user` operation in various forms, with the result of this operation +being the instantiation of an `OpenerResource` configured for the indicated +user identity. + +== Registries == + +The basic mechanism for obtaining a resource involves a registry, as +illustrated by the following diagram. + +######## A graph showing the use of a registry in obtaining resources + +{{{#!graphviz +#format svg +#transform notugly +digraph registry { + node [fontsize="12.0",fontname="sans-serif",shape=box]; + edge [fontsize="12.0",fontname="sans-serif"]; + rankdir=LR; + + subgraph { + node [label="OpenerContextResource"]; + rank=same; + + OpenerContextResource1 -> OpenerContextResource2 [dir=none,style=dotted]; + } + + subgraph { + node [label="OpenerResource"]; + rank=same; + + OpenerResource1 -> OpenerResource2 [dir=none,style=dotted]; + } + + subgraph { + rank=same; + + ResourceRegistry -> Resource; + } + + subgraph { + rank=same; + + ProviderRegistry -> Provider; + } + + OpenerContextResource1 -> OpenerResource1 [label="open"]; + OpenerResource1 -> ResourceRegistry [label="get_resource"]; + ResourceRegistry -> ProviderRegistry [label="get/set"]; + + Provider -> Resource -> OpenerResource2 -> OpenerContextResource2; +} +}}} + +######## + +The `ResourceRegistry` coordinates access to filesystem resources and, through +synchronisation, prevents conflicting operations from occurring concurrently. +For example, a removal operation on a file may not be allowed to occur while +an opening operation is in progress. + +To achieve this, a common lock is employed to serialise access, with any +underlying filesystem operations being initiated from the registry while the +lock is held. An object providing the `FileOpening` interface for a filesystem +provides such operations, and the following interaction pattern is thereby +employed: + +######## A graph showing the registry coordinating filesystem operations + +{{{#!graphviz +#format svg +#transform notugly +digraph registry_operations { + node [fontsize="12.0",fontname="sans-serif",shape=box]; + edge [fontsize="12.0",fontname="sans-serif"]; + rankdir=LR; + + OpenerContextResource -> OpenerResource -> ResourceRegistry -> FileOpening; +} +}}} + +######## + +Since the `ResourceRegistry` functionality is generic, it could be specialised +for each filesystem or be configured with an appropriate reference to a +`FileOpening` object. The `OpenerResource` would then be generic, invoking the +registry which would, in turn, invoke the opening object. + +However, the chosen approach is to permit `OpenerResource` objects to +implement the `FileOpening` interface for each filesystem, meaning that the +`ResourceRegistry` will end up being called by the opener and then invoking +the opener in return. This is slightly more convenient than the alternative +since the opener can be configured with a given user identity, and such +identity details will ultimately be employed when accessing the underlying +filesystem itself.