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. _______________________________________________ Bug-hurd mailing list Bug-hurd@gnu.org http://lists.gnu.org/mailman/listinfo/bug-hurd