bug-hurd
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GSoC libchannel] Specification


From: Carl Fredrik Hammar
Subject: [GSoC libchannel] Specification
Date: Fri, 13 Jul 2007 17:35:59 +0200
User-agent: Gnus/5.1008 (Gnus v5.10.8) Emacs/22.1.50 (gnu/linux)

Hello,

this is my first atempt at a (mostly) complete specification for
libchannel.  Perhaps a bit to detailed and lenghty to give a nice
overview, but I trust you can filter out the noise.

I would appreciate it if Richard, Roland and Marcus would have a look
at it.  But also from anybody else, ofcourse.

Regards,
  Fredrik


Overview
========

libchannel will provide a channel abstraction similar to libstore's
stores and will mostly be used for implementing character device
files.  As such the primary operations will be basic io.

The main difference from a stripped down libstore will be that classes
can support any number of interfaces in addition to io, without any
change needed to libchannel, channelio or any other channel
translator.


Channel
=======

The channel struct has the following fields.

file_t source

  The file from which we got our channel if it was created using
  channel_fetch.  Closed by channel_free.

char *name

  The name of this channel.  It's meaning is class-specific.
  May be null and is freed by channel_free.

mach_port_t port

  A port used for a class-specific purpose.  May be null and is
  deallocated by channel_free.

int flags

  Various flags used by the channel and it's class.  See flags section
  for available flags.

struct channel_class const *class

  The class of this channel.  See class section.

struct channel_interface *const *interfaces
int num_interfaces

  List of interfaces implemented by this channel.  May be null and is
  freed by channel_free.  See interface section.

struct channel **children
size_t num_children

  A list of sub-channels.  May be null and it and contained children
  are freed by channel_free.  See sub-channel section.

void *hook

  Extra data used by the channel's class and interfaces.  *Not* freed
  by channel_free.

struct interface_hook *interface_hooks
size_t num_interface_hooks

  Extra data used by interfaces.  The vector is freed by channel_free,
  but the hooks themselves.

XXX fields in store which have no equivalent in channel:
  runs, num_runs, end, wrap_src, wrap_dst, block_size, blocks, size,
  log2_block_size, log2_blocks_per_page, misc, misc_len.

Fields of interface_hook.

int id

  The id of the interface this hook is for.

void *data

  Extra data used by the interface. *Not* freed by channel_free.


Class
=====

The class struct has the following fields.

enum file_storage_class id

  The id of this class (see CHANNEL_* in hurd/hurd_types.h)

const *name

  The class's name.

error_t (*read) (struct channel *channel, size_t amount,
                 void **buf, size_t *len)

  Read at most AMOUNT bytes from CHANNEL into BUF and LEN with the
  usual return buf semantics.  Should block until data is available or
  return 0 bytes on EOF.  May not be null.  See channel_read.

  XXX store's read method uses mach_msg_number_t instead of size_t,
  but what's the point if store_read uses size_t?

error_t (*write) (struct channel *channel,
                  const void *buf, size_t len,
                  size_t *amount)

  Write LEN bytes from BUF to CHANNEL, AMOUNT is set to the amount
  actually witten.  Should block until data can be written.  May not
  be null.  See channel_write.

  XXX store's write method uses mach_msg_number_t instead of size_t,
  but what's the point if store_write uses size_t?

error_t (*set_flags) (struct channel *channel, int flags)

  Set any backend handled flags in CHANNEL specified in FLAGS.  May be
  null.  See channel_set_flags.

error_t (*clear_flags) (struct channel *channel, int flags)
  
  Clear any backend handled flags in CHANNEL specified in FLAGS.  May
  be null.  See channel_clear_flags.

error_t (*clone) (const channel *from, struct channel *to)

  Copy any class specific parts of FROM to TO.  May be null.  See
  channel_clone.

error_t (*open) (const char *name, int flags,
                 const struct channel_class *const *classes,
                 struct channel **channel)

  Open NAME with given FLAGS and return it as a new channel in
  CHANNEL.  The interpretation of NAME is class-specific.  CLASSES are
  provided in order to open any sub-channels.

error_t (*allocate_encoding) (const struct channel *channel,
                              struct channel_enc *enc)

  Increase the lengths of the arrays in ENC by what is needed to
  encode CHANNEL (not just class-specific parts.)  May be null.  See
  channel_enc and channel_encode.

error_t (*encode) (const struct channel *channel,
                   struct channel_enc *enc)

  Append encoding of CHANNEL to ENC at the respective position of each
  cursor and update their positions.  See channel_enc and
  channel_encode

error_t (*decode) (struct channel_enc *enc,
                   const struct channel_class *const *classes,
                   struct channel **channel)

  Decode from ENC a new store ad return it in CHANNEL.  Look up any
  child classes in CLASSES.  May be null.  See channel_enc and
  channel_decode.

void (*cleanup) (struct channel *channel)

  Free any class-specific resources allocated for CHANNEL.  May be
  null.

Classes are, by default, searched for in the `channel_std_classes'
section of the executable and in all loaded shared objects.  Through
out this document all these classes are refered to as
`channel_std_classes'.

Here's a utility function that finds already loaded classes by name.

const struct channel_class *
channel_find_class (const char *name, const char *name_end,
                    const struct channel *const *classes)

  Find and return a channel class by name in CLASSES if not null,
  otherwise in the `channel_std_class' section and already loaded
  modules.  NAME_END points to the character after the class name in
  NAME; if null, then NAME is the null-terminated class name.


Interface
=========

libchannel is primarily intended to be used to implement character
devices and these often provide subsystems beyond normal i/o,
traditionally this is privided through the ioctl syscall.  As such,
channel classes will want to support subsystems unknown by libchannel
and any translator that is using it to provide access to channels.

These interfaces are intended to control i/o of the channel, but the
only real restriction is that they opperate on a port that can be
mapped to a underlying channel.

A channel that implements a IPC interface will need to provide a
corresponding channel interface in it's set of interfaces.  Here are
the fields of the channel_interface struct.

int id

  This id must be the same as the id of the subsystem the interface
  implements.

int (*demuxer) (mach_msg_header_t *in, mach_msg_header_t *out)

  The demuxer which should forward any RPC to a corresponding method
  in the methods field.  To forward the RPC you need to look up this
  channel interface with channel_trans_find_channel and
  channel_find_interface.

void *methods

  Points to a table of function pointers that implement the procedures
  defined by the subsystem.  They are to be called from the demuxer,
  which knows their proper type.

The demuxer and the type of the method table should be class
independant and shared by all classes that supports them.

If a class supports an interface it should provide a method table for
it and the methods themselves.  A class is responsible to add any
interfaces that are implemented by a channel to it's set of
interfaces.  A channel can implement any number of interfaces
supported by it's class.

XXX possible extension: attempt to load interfaces dynamically, with
one module per class, interface pair.  I'm not sure how useful this
might be, as simply bundling them with class modules seems natrual.

The channel and interface is known when demuxer is succesfully called,
but unfortunately we can't communicate this directly to the demuxer
itself.  Therefor the following functions are provided.

error_t
channel_trans_find_channel (mach_port_t port,
                            struct channel **channel)

  Find and return in CHANNEL the channel that underlies PORT.  This
  function should be overridden by the translator using libchannel, as
  the default implementation will always fail with EOPNOTSUPP.

  XXX channel_t *channel_trans_find_channel (mach_port_t) might be
  more useful signature, as it can be used as a mig intrans function.
  But how should errors be handled?

error_t
channel_find_interface (const *channel, int id
                        channel_interface_t *const *interface)

  Find and return in INTERFACE the interface in CHANNEL with id ID.

It makes sense to bundle functions that wrap methods and does the
method lookup, with the type of the method table.  These would be
useful for code opperating directly with the channels.


(De)allocation
==============

error_t
channel_create (const struct channel_class *class, int flags, 
                struct channel **channel)

  Allocate a new channel of class CLASS, with flags in FLAGS set
  (using channel_set_flags,) that is returned in CHANNEL.  Return
  ENOMEM if memory for channel couldn't be allocated.

error_t
channel_clone (const struct channel *from, struct channel **to)

  Return in TO a newly allocated copy of FROM and call clone method to
  copy any class-specific bits.  Return ENOMEM if copy couldn't be
  allocated.

void
channel_free (struct channel *channel)

  If not-null call method cleanup to deallocate class-specific bits of
  CHANNEL, then free it (regardless) and any generic resources used by
  it.


Open and close
==============

error_t
channel_fetch (file_t source, int flags,
               const struct channel_class *const *classes,
               struct channel **channel)

  Return a new channel in CHANNEL, which is a copy of the channel
  underlying SOURCE.  The class of CHANNEL is found in CLASSES or
  CHANNEL_STD_CLASSES, if CLASSES is null.  FLAGS is set with
  channel_set_flags.  Keeps the SOURCE reference, it may be closed
  with channel_close_source.

  XXX libstore's version of this function is called store_create, but
  I found this name confusing.  It also forces the allocate function
  to be called _store_create. (yuck!)

  XXX libstore treats inactive flag special, libchannel lacks this
  flag (for now.)

error_t
channel_open (const char *name, int flags
              const struct channel_class *const *classes,
              struct channel **channel)

  Open the file NAME and return a new channel in CHANNEL, which is
  either a copy of the file's underlying channel or a channel using it
  through file io, unless CHANNEL_NO_FILEIO flag is given.  The class
  of CHANNEL is found in CLASSES or CHANNEL_STD_CLASSES, if CLASSES is
  null.  FLAGS is set with channel_set_flags.  Keeps the SOURCE
  reference, it may be closed with channel_close_source.

void
store_close_source (struct channel *channel)

  Remove the reference to the source of CHANNEL, from which it was
  created.


I/O
===

As simple as can be!  Apart from checking some permission flags they
are just wrappers for corresponding methods.

error_t
channel_read (struct channel *channel, size_t amount,
              void **buf, size_t *len)

  Reads at most AMOUNT bytes from CHANNEL into BUF and LEN with the
  usual return buf semantics.  Blocks until data is available and
  returns 0 bytes on EOF.

  If channel is write-only return EPERM, otherwise forward call to
  read method.  XXX alternatively EACCES or EOPNOTSUPP.

channel_write (channel, buf, *amount)

  Write LEN bytes of BUF to CHANNEL, AMOUNT is set to the amount
  actually witten.  Blocks until data can be written.

  If channel is read-only return EPERM, otherwise forward call to read
  method.  XXX alternatively EACCES, EROFS or EOPNOTSUPP.


Flags
=====

The following flags are used and handled by the generic channel code.

CHANNEL_READONLY
  Reading from channel not allowed.

CHANNEL_WRITEONLY
  Writing from channel not allowed.

CHANNEL_NO_FILEIO
  Don't do file io as an alternative to fetching underlying storage.

CHANNEL_GENERIC_FLAGS
  An or of the above flags.

CHANNEL_BACKEND_SPEC_BASE
  Here on up it's class specific flags.

CHANNEL_BACKEND_FLAGS
  An or of all flags that should be handled by classes.

Any backend flag that is generally usefull to handle should also be
put here, but I'll wait until I actually have some backends before I
define any of them (a la STORE_INACTIVE, STORE_INNOCUOUS, etc.)

error_t
channel_set_flags (struct channel *channel, int flags)

  Set the flags FLAGS in CHANNEL.  Remove any already set flags in
  FLAGS, if FLAGS then contain backend flags call set_flags method
  with with FLAGS or if set_flags is null return EINVAL.  Lastly
  generic flags get set.

error_t
channel_clear_flags (struct channel *channel, int flags)

  Clear the flags FLAGS in CHANNEL.  Remove any already cleared flags
  in FLAGS, if FLAGS then contain backend flags call clear_flags
  method with with FLAGS or if clear_flags is null return EINVAL.
  Lastly generic flags get clear.


Misc.
=====

channel_set_name (*channel, *name)

  Set name of CHANNEL to copy of NAME.  Return ENOMEM if no memory if
  available.


Sub-channels
============

If a channel is layered on-top of other channels, the later are said
to be the former's children.

error_t
channel_set_children (struct channel *channel,
                      struct store *const *children, size_t num_children)

  Set the CHANNEL's list of children to a copy of CHILDREN and
  NUM_CHILDREN, or if allocation fails return ENOMEM.

error_t
channel_allocate_child_encodings (const struct channel *channel,
                                  struct channel_enc *enc)

  Calls allocate_encoding method on each child of CHANNEL propagating
  any error or if any child does not have the method, return
  EOPNOTSUPP.

error_t
channel_encode_children (const struct channel *channel,
                         struct channel_enc *enc)

  Calls encode method on each child of CHANNEL propagating any error
  or if any child does not have the method, return EOPNOTSUPP.

error_t
channel_decode_children (struct channel_enc *enc, size_t num_children
                         const struct channel_class *const *classes,
                         struct store **children)

  Decode NUM_CHILDREN from ENC and store the result in CHILDREN,
  propagating any errors.

error_t
channel_set_child_flags (struct channel *channel, int flags)

  Set FLAGS in all the children of CHANNEL, and if successful, set
  them in CHANNEL also.  Flags are set as if using channel_set_flags.
  Propagate any error on failure.

error_t
channel_clear_child_flags (struct channel *channel, int flags)

  Clear FLAGS in all the children of CHANNEL, and if successful, clear
  them in CHANNEL also.  Flags are cleared as if using
  channel_clear_flags.  Propagate any error on failure.

error_t
channel_open_children (const char *name, int flags,
                       const struct channel_class *const *classes,
                       struct channel ***channels, size_t *num_channels)

  Parse multiple channel names in NAME, opening and returning each in
  CHANNELS and NUM_CHANNELS.  The syntax of name is a single
  non-alpha-numeric character followed by each child store name,
  seperated by the same separator.  Each child name is in TYPE:NAME
  notation as parsed by channel_typed_open.  If all children has the
  same TYPE: prefix, then it may be factored out and put before the
  child list instead.

error_t
channel_children_name (const struct *channel, char **name)

  Generate a name for the children in CHANNEL into NAME.  It done by
  combining the name of each child in a way that the name can be
  parsed by channel_open_children.  This is done heuristically, and it
  may fail and return EGRATUITOUS.  If a child does not have a name,
  return EINVAL.  If memory is exausted, return ENOMEM.


IPC encoding
============

The struct channel_enc holds the various bits that make up the
representation of a channel that are is to be returned by
file_get_channel_info.  The struct itself is only used during the
encoding and decoding processes.

Since the channel is implemented by several parties, i.e. libchannel,
channel class and possibly sub-channel classes, each party must fill
the vectors by them selves at the position of the vectors' cursors.
Before this the vectors must be allocated, the size needed are
gathered in a similar fashion, by allowing each party to increment the
vectors' sizes.

The only constrait of the encoding if that the first int of an
encoding (i.e. at cursor's position) should hold the class's id field,
since it's needed to find the class when decoding.

channel_enc has the following fields.

mach_port_t *ports

  Any ports used by the channel should be put here.  Might be mmapped,
  see init_ports field.

int *ints

  Any ints should be put here.  Might be mmapped,
  see init_ints field.

void *data

  Any other data for the channel should be put here, typically
  strings.  Might be mmapped, see init_data field.

size_t num_ports, num_ints, data_len

  Size of the respective vector.

mach_port_t *cur_port
int *cur_int
void *cur_data

  Cursor for the respective vector.

mach_port_t *init_ports
int *init_ints
void *init_data

  Initial value for the respective vector, these were not allocated by
  encoding rutines and should not be freed by channel_enc_dealloc.


The following (de)allocation functions.

error_t
channel_enc_init (struct channel_enc *enc,
                  mach_port_t *ports, size_t num_ports,
                  int *ints, size_t num_ints,
                  void *data, size_t data_len)

  Sets the various fields of ENC.  The given vectors and sizes will be
  used for storing the encoding if they are big enough, otherwise new
  ones are allocated.

void
channel_enc_dealloc (struct channel_enc *enc)

  Deallocate any resorces that was allocated for ENC by encoding
  routines.

XXX libstore also provides store_enc_return, but it's only used in
store_return.  Providing both seems a bit redundant, so I dropped it.

error_t
channel_encode (const struct channel *channel,
                struct channel_enc *enc)

  Encode CHANNEL into ENC, using allocate_encoding and encode methods.
  If one of the methods is null, return EOPNOTSUPP, or if other error
  occurs return it.  ENC should be prepared with channel_enc_init
  beforehand.  The allocate_encode method to ensure that there is
  enough room for the encoding and new space is allocated if not.

  The resulting ENC may then be retured by file_get_channel_info rpc,
  or if it failed, can use channel_enc_dealloc to deallocate used
  resorces.

error_t
channel_std_leaf_encode (const struct channel *channel,
                         struct channel_enc *enc)
error_t
channel_std_leaf_alloacate_encoding (const struct channel *channel,
                                     struct channel_enc *enc)

  Standard encoding/allocation method-pair implementations used for
  most leaf channel classes.  It encodes the generic data of a
  channel, that isn't class-specific. XXX specify encoded data,
  include interface ids.

error_t
channel_return (const struct channel *channel,
                mach_port_t **ports, size_t *num_ports,
                int **ints, size_t *num_ints,
                void **data, size_t *data_len)

  Encode CHANNEL into the output parameters or return error.  Suitable
  for returning from a file_get_channel_info rpc.

error_t
channel_decode (struct channel_enc *enc, 
                const struct channel_class *const *classes,
                struct channel **channel)

  Decode ENC using return new channel in CHANNEL or return an error.
  If not null CLASSES maps class-ids to classes, otherwise
  CHANNEL_STD_CLASSES is used.  The decode method class of ENC, as
  found in the class-id to class mapping, is used to decode it and is
  also supplied with said mapping.

error_t
channel_std_leaf_decode (struct channel_enc *enc,
                         struct channel **channel)

  Standard leaf channel decode method (for encodings made by
  channel_std_leaf_encode) and return it in STORE.


Modules
=======

If linked with -lchannel_modules -ldl (which is the case of the shared
libchannel), these functions that load channel classes dynamically are
also provided.  Class modules are provied through both
`li!bchannel_$(class).so' and `libchannel_type-$(id).so, if it wasn't
found in the other locations.

error_t
channel_module_find_class (const char *name, const char *name_end,
                           const struct channel_class **class)

  Load the module that defines the class NAME (upto NAME_END) and
  return it in CLASS.  Return ENOENT if module isn't available, or any
  other error code from dlopen and friends if module couldn't be
  loaded.

  XXX libstore's store_module_find_class gets the class through the
  symbol `store_NAME_class', instead of searching `store_std_classes'.
  But that seems a bit inconsistant with other module loading
  functions.

error_t
channel_module_open (const char *name, int flags,
                     const struct channel *const *classes,
                     struct channel **channel)

  Open and return in CHANNEL, the channel specified by NAME, which
  should consist of a channel type name followed by a `:' and any
  type-specific name.  It's class is loaded dynamically and CLASSES is
  only passed to the class's open method (which usually use it for
  parsing sub-channels in it's name.)

  XXX libstore's version has same inconsistency as in
  store_module_find_class.

error_t
channel_module_decode (struct channel_enc *enc,
                       const struct channel_class *const *classes,
                       struct channel **channel)

  Find a module capable of decoding ENC, decode it and return it in
  CHANNEL.  Unlike other module functions it looks for module
  `libchannel_type-ID.CHANNEL_SONAME_SUFFIX', i.e. by id rather than
  name.  Return ENOENT if module isn't available, or any other error
  code from dlopen and friends if module couldn't be loaded.  CLASSES
  is passed to the loaded channel class's decode method for use in
  decoding sub-channels.


Remote procedures
=================

This routine will be defined in `hurd/fs.defs'.

routine file_get_channel_info (
        file: file_t;
        RPT
        out ports: portarray_t, dealloc;
        out ints: intarray_t, dealloc;
        out data: data_t, dealloc);

  Return information on channel underlying this file.




reply via email to

[Prev in Thread] Current Thread [Next in Thread]