L4Re/departure

docs/wiki/Components

360:92c5f6aa8c36
2022-06-12 Paul Boddie Reintroduced PagerObject code generation required to initiate servers. mmap-region-flags
     1 = Components =     2      3 Access to files is provided by a number of programs acting as components. For     4 convenience, the component-level operations are wrapped up in a     5 [[ClientLibrary|client library]] that aims to provide simpler, more familiar     6 mechanisms for opening, reading, writing, and closing files, together with     7 various other operations.     8      9 <<TableOfContents(2,3)>>    10     11 Components are accessed via interfaces defined using the interface description    12 language supported by the ``idl4re`` tool. Interface operations in this    13 document are described using excerpts from the appropriate interface    14 descriptions.    15     16 == Overview ==    17     18 An overview of the component interactions involved in opening a file or    19 directory is provided by the diagram below.    20     21 ######## A graph showing the interactions between components    22     23 {{{#!graphviz    24 #format svg    25 #transform notugly    26 digraph components {    27   node [fontsize="12.0",fontname="sans-serif",shape=box];    28   edge [fontsize="12.0",fontname="sans-serif"];    29   rankdir=LR;    30     31   subgraph {    32     node [label="Client"];    33     rank=min;    34     35     Client1; Client2; Client3; Client4; Client5; Client6; Client7;    36   }    37     38   subgraph {    39     rank=same;    40     41     Memory [label="filename",shape=note];    42   }    43     44   subgraph {    45     rank=max;    46     47     Filesystem;    48     49     subgraph {    50       node [label="Opener\n(user)"];    51       Opener1; Opener2;    52     }    53     54     subgraph {    55       node [label="OpenerContext"];    56       OpenerContext1; OpenerContext2; OpenerContext3;    57     }    58     59     Object [label="MappedFile\nor\nDirectory"];    60   }    61     62   Client1 -> Client2 -> Client3 -> Client4 -> Client5 -> Client6 -> Client7 [arrowhead=none,style=dotted];    63   Opener1 -> Opener2 [arrowhead=none,style=dotted];    64   OpenerContext1 -> OpenerContext2 -> OpenerContext3 [arrowhead=none,style=dotted];    65     66   Client1 -> Filesystem [label="open_for_user(user)"];    67   Filesystem -> Opener1;    68   Opener1 -> Client2;    69     70   Client3 -> Opener2 [label="context()"];    71   Opener2 -> OpenerContext1;    72   OpenerContext1 -> Client4;    73     74   Client5 -> Memory -> OpenerContext2;    75     76   Client6 -> OpenerContext3 [label="open(flags, ...)"];    77   OpenerContext3 -> Object;    78   Object -> Client7;    79 }    80 }}}    81     82 ########    83     84 In pseudocode, the operations as conducted by the client program are as    85 follows:    86     87 {{{    88 opener = filesystem.open_for_user(user)    89 context = opener.context()    90 context.write("filename") # this being a memory access operation    91 file = context.open(flags, ...)    92 }}}    93     94 Reading from an opened directory is achieved as shown in the following    95 diagram.    96     97 ######## A graph showing the interactions between components    98     99 {{{#!graphviz   100 #format svg   101 #transform notugly   102 digraph components {   103   node [fontsize="12.0",fontname="sans-serif",shape=box];   104   edge [fontsize="12.0",fontname="sans-serif"];   105   rankdir=LR;   106    107   subgraph {   108     node [label="Client"];   109     rank=min;   110    111     Client1; Client2; Client3; Client4;   112   }   113    114   subgraph {   115     rank=same;   116    117     Memory [label="entries",shape=note];   118   }   119    120   subgraph {   121     rank=max;   122    123     Directory;   124    125     subgraph {   126       node [label="Reader"];   127    128       Reader1; Reader2; Reader3;   129     }   130   }   131    132   Client1 -> Client2 -> Client3 -> Client4 [arrowhead=none,style=dotted];   133   Reader1 -> Reader2 -> Reader3 [arrowhead=none,style=dotted];   134    135   Client1 -> Directory [label="opendir()"];   136   Directory -> Reader1;   137   Reader1 -> Client2;   138    139   Client3 -> Reader2 [label="current_region()"];   140   Reader3 -> Memory -> Client4;   141 }   142 }}}   143    144 ########   145    146 In pseudocode, the operations as conducted by the client program are as   147 follows:   148    149 {{{   150 reader = directory.opendir()   151 reader.current_region()   152 entries = reader.read() # this being a memory access operation   153 }}}   154    155 == Filesystems ==   156    157 Filesystems implement the `Filesystem` interface which provides the   158 `open_for_user` operation:   159    160 {{{   161 open_for_user(in user_t user, out cap opener)   162 }}}   163    164 The operation yields a file opener appropriate for the given [[Users|user]]   165 credentials.   166    167 == File Openers ==   168    169 File openers implement the `Opener` interface which provides the `context`   170 operation:   171    172 {{{   173 context(out cap context)   174 }}}   175    176 Each client program, task or thread obtains its own context because it will   177 need its own dedicated channel for communication with the filesystem.   178    179 == Opener Contexts ==   180    181 An opener context acts as a dataspace, meaning that it can be attached to a   182 task using a region manager and provide a buffer via a region of mapped memory   183 that the task can write to. In the case of a context, the task will write a   184 filesystem path indicating the file to be opened.   185    186 Each context allows a client program to request access to individual files via   187 operations provided by the `OpenerContext` interface, of which the most   188 pertinent is the `open` operation:   189    190 {{{   191 open(in flags_t flags, out offset_t size, out cap file,   192      out object_flags_t object_flags)   193 }}}   194    195 Using the path information written to the context's memory region, the `open`   196 operation will obtain a reference to a file-like object whose characteristics   197 are described by the accompanying `object_flags`, these helping the client to   198 distinguish between files that support arbitrary memory mapping operations and   199 pipes that mandate sequential region-by-region access.   200    201 Alongside regular files, directories may also be opened. Reading from them   202 yields a listing of directory entries.   203    204 === Removing ===   205    206 Filesystem objects are removed by invoking the `remove` operation on an opener   207 context:   208    209 {{{   210 remove()   211 }}}   212    213 The path information identifying the object must first be written to the   214 context's memory region.   215    216 === Renaming ===   217    218 Filesystem objects are renamed by invoking the `rename` operation on an opener   219 context:   220    221 {{{   222 rename()   223 }}}   224    225 The path information of the affected object and the destination of the rename   226 operation must first be written to the context's memory region. The   227 destination path follows immediately after the terminating byte of the   228 affected path.   229    230 === Statistics/Metadata ===   231    232 Statistics or metadata for a filesystem object can be obtained by invoking the   233 `stat` operation on an opener context:   234    235 {{{   236 stat()   237 }}}   238    239 The path information identifying the object must first be written to the   240 context's memory region. As a result of the invocation, a `stat` data   241 structure will be written to the start of the memory region.   242    243 == Files ==   244    245 Files themselves act as dataspaces, meaning that they can be attached to a   246 task using a region manager and provide their content via a region of mapped   247 memory. Files implement the `MappedFile` interface.   248    249 Control over the region of the file provided via mapped memory occurs   250 using the `mmap` operation:   251    252 {{{   253 mmap(in offset_t position, in offset_t length,   254      in offset_t start_visible, in offset_t end_visible,   255      out offset_t start_pos, out offset_t end_pos,   256      out offset_t size)   257 }}}   258    259 Files also implement the more general `File` interface that provides the   260 `resize` operation:   261    262 {{{   263 resize(inout offset_t size)   264 }}}   265    266 This allows the portion of the memory region dedicated to the file's contents   267 to be extended.   268    269 == Directories ==   270    271 Directories are obtained, like files, using the `open` operation. They   272 implement the `Directory` interface.   273    274 To read directory listings, the `opendir` operation is used to obtain a   275 directory reader:   276    277 {{{   278 opendir(out offset_t size, out cap file, out object_flags_t object_flags)   279 }}}   280    281 Directory readers are meant to be accessed like files, meaning that it should   282 be possible to attach them to a task using a region manager and access the   283 provided content, this being a listing of directory entries, via the mapped   284 region.   285    286 However, unlike files which may support arbitrary mapping of their contents,   287 the provided content may be supplied by a pipe endpoint, thereby not   288 supporting precisely the same navigation mechanisms as those supported by   289 files.   290    291 == Pipe Openers ==   292    293 Distinct from filesystems but potentially used by them, pipe openers provide a   294 means of obtaining pipes, which are channels that support unidirectional   295 communication via shared memory.   296    297 Pipe openers implement the `PipeOpener` interface and support the following   298 operation:   299    300 {{{   301 pipe(in offset_t size, out cap reader, out cap writer)   302 }}}   303    304 The size is indicated to request pipe regions long enough for the needs of the   305 communicating parties, with both reader and writer endpoint capabilities being   306 returned. Such capabilities may be propagated to the eventual parties, these   307 typically being separate tasks.   308    309 == Pipes ==   310    311 Although not generally obtained from filesystems, pipes may be involved in   312 providing content from some filesystem objects such as directories. However,   313 they are also obtained directly from an appropriate pipe server providing pipe   314 opening facilities.   315    316 Pipes expose single regions of shared memory to their endpoints, with the   317 writing endpoint populating one region while the reading endpoint accesses the   318 other. The reading endpoint may advance to the region being written, and this   319 will free up a new region for the writer when it has filled its region. When   320 the writer itself advances, it permits the reader to consume all data in the   321 fully populated region. Naturally, the reader may not advance ahead of the   322 writer.   323    324 Pipes implement the `Pipe` interface and a number of operations to support   325 this interaction mechanism.   326    327 The details of an endpoint's current region can be queried using the following   328 operation:   329    330 {{{   331 current_region(out offset_t populated_size, out offset_t size)   332 }}}   333    334 This provides details of the populated size (or amount of written data) in a   335 region along with the size of the region.   336    337 Navigation to the next available region of the pipe is performed using the   338 following operation:   339    340 {{{   341 next_region(inout offset_t populated_size, out offset_t size)   342 }}}   343    344 Here, the populated size may be specified by the writer so that the reader may   345 query the current region's properties using the appropriate operation.   346    347 The status of the pipe can be queried using the `closed` operation:   348    349 {{{   350 closed(out int closed)   351 }}}   352    353 This indicates through a boolean-equivalent parameter whether one or both   354 endpoints have been closed.