⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fileio.txt

📁 开放源码实时操作系统源码.
💻 TXT
📖 第 1 页 / 共 2 页
字号:
infrastructure, any changes to it must be made with the appropriate
logical operations.


Directories
-----------

Filesystem operations all take a directory pointer as one of their
arguments.  A directory pointer is an opaque handle managed by the
filesystem. It should encapsulate a reference to a specific directory
within the filesystem. For example, it may be a pointer to the data
structure that represents that directory, or a pointer to a pathname
for the directory.

The _chdir_ filesystem function has two modes of use. When passed a
pointer in the _dir_out_ argument, it should locate the named
directory and place a directory pointer there. If the _dir_out_
argument is NULL then the _dir_ argument is a previously generated
directory pointer that can now be disposed of. When the infrastructure
is implementing the chdir() function it makes two calls to filesystem
_chdir_ functions. The first is to get a directory pointer for the new
current directory. If this succeeds the second is to dispose of the
old current directory pointer.

The _opendir_ function is used to open a directory for reading. This
results in an open file object that can be read to return a sequence
of _struct dirent_ objects. The only operation that are allowed on
this file are _read_, _lseek_ and _close_. Each read operation on this
file should return a single _struct dirent_ object. When the end of
the directory is reached, zero should be returned. The only seek
operation allowed is a rewind to the start of the directory, by
supplying an offset of zero and a _whence_ specifier of _SEEK_SET_.

Most of these considerations are invisible to clients of a filesystem
since they will access directories via the POSIX
opendir()/readdir()/closedir() functions.

Support for the _getcwd()_ function is provided by three mechanisms.
The first is to use the _FS_INFO_GETCWD_ getinfo key on the filesystem
to use any internal support that it has for this. If that fails it
falls back on one of the two other mechanisms. If
_CYGPKG_IO_FILEIO_TRACK_CWD_ is set then the current directory is
tracked textually in chdir() and the result of that is reported in
getcwd(). Otherwise an attempt is made to traverse the directory tree
to its root using ".." entries.

This last option is complicated and expensive, and relies on the
filesystem supporting "." and ".."  entries. This is not always the
case, particularly if the filesystem has been ported from a
non-UNIX-compatible source. Tracking the pathname textually will
usually work, but might not produce optimum results when symbolic
links are being used.


Synchronization
---------------

The FILEIO infrastructure provides a synchronization mechanism for
controlling concurrent access to filesystems. This allows existing
filesystems to be ported to eCos, even if they do not have their own
synchronization mechanisms. It also allows new filesystems to be
implemented easily without having to consider the synchronization
issues.

The infrastructure maintains a mutex for each entry in each of
the main tables: filesystem table, mount table and file table. For
each class of operation each of these mutexes may be locked before the
corresponding filesystem operation is invoked.

The synchronization protocol implemented by a filesystem is described
by the _syncmode_ field of the filesystem table entry. This is a
combination of the following flags:

CYG_SYNCMODE_FILE_FILESYSTEM Lock the filesystem table entry mutex
			     during all filesystem level operations.

CYG_SYNCMODE_FILE_MOUNTPOINT Lock the mount table entry mutex
			     during all filesystem level operations.

CYG_SYNCMODE_IO_FILE	     Lock the file table entry mutex during all
			     I/O operations.

CYG_SYNCMODE_IO_FILESYSTEM   Lock the filesystem table entry mutex
			     during all I/O operations.
			     
CYG_SYNCMODE_IO_MOUNTPOINT   Lock the mount table entry mutex during
			     all I/O operations.

CYG_SYNCMODE_SOCK_FILE       Lock the file table entry mutex during
			     all socket operations.

CYG_SYNCMODE_SOCK_NETSTACK   Lock the network stack table entry mutex
			     during all socket operations.

CYG_SYNCMODE_NONE	     Perform no locking at all during any
			     operations.


The value of the _syncmode_ in the filesystem table entry will be
copied by the infrastructure to the open file object after a
successful open() operation.


Initialization and Mounting
---------------------------

As mentioned previously, mount table entries can be sourced from two
places. Static entries may be defined by using the MTAB_ENTRY()
macro. Such entries will be automatically mounted on system startup.
For each entry in the mount table that has a non-null _name_ field the
filesystem table is searched for a match with the _fsname_ field. If a
match is found the filesystem's _mount_ entry is called and if
successful the mount table entry marked valid and the _fs_ field
initialized. The _mount_ function is responsible for initializing the
_root_ field.

The size of the mount table is defined by the configuration value
CYGNUM_FILEIO_MTAB_MAX. Any entries that have not been statically
defined are available for use by dynamic mounts.

A filesystem may be mounted dynamically by calling mount(). This
function has the following prototype:

int mount( const char *devname,
           const char *dir,
	   const char *fsname);

The _devname_ argument identifies a device that will be used by this
filesystem and will be assigned to the _devname_ field of the mount
table entry.

The _dir_ argument is the mount point name, it will be assigned to the
_name_ field of the mount table entry.

The _fsname_ argument is the name of the implementing filesystem, it
will be assigned to the _fsname_ entry of the mount table entry.

The process of mounting a filesystem dynamically is as follows. First
a search is made of the mount table for an entry with a NULL _name_
field to be used for the new mount point. The filesystem table is then
searched for an entry whose name matches _fsname_. If this is
successful then the mount table entry is initialized and the
filesystem's _mount_ operation called. If this is successful, the
mount table entry is marked valid and the _fs_ field initialized.

Unmounting a filesystem is done by the umount() function. This can
unmount filesystems whether they were mounted statically or
dynamically.

The umount() function has the following prototype:

int umount( const char *name );

The mount table is searched for a match between the _name_ argument
and the entry _name_ field. When a match is found the filesystem's
_umount_ operation is called and if successful, the mount table entry
is invalidated by setting its _valid_ field false and the _name_ field
to NULL.

Sockets
-------

If a network stack is present, then the FILEIO infrastructure also
provides access to the standard BSD socket calls.

The netstack table contains entries which describe the network
protocol stacks that are in the system image. Each resident stack
should export an entry to this table using the NSTAB_ENTRY() macro.

Each table entry has the following structure:

struct cyg_nstab_entry
{
    cyg_bool            valid;          // true if stack initialized
    cyg_uint32          syncmode;       // synchronization protocol
    char                *name;          // stack name
    char                *devname;       // hardware device name
    CYG_ADDRWORD        data;           // private data value

    int     (*init)( cyg_nstab_entry *nste );
    int     (*socket)( cyg_nstab_entry *nste, int domain, int type,
		       int protocol, cyg_file *file );
};

This table is analogous to a combination of the filesystem and mount
tables.

The _valid_ field is set true if the stack's _init_ function returned
successfully and the _syncmode_ field contains the CYG_SYNCMODE_SOCK_*
bits described above.

The _name_ field contains the name of the protocol stack.

The _devname_ field names the device that the stack is using. This may
reference a device under "/dev", or may be a name that is only
meaningful to the stack itself.

The _init_ function is called during system initialization to start
the protocol stack running. If it returns non-zero the _valid_ field
is set false and the stack will be ignored subsequently.

The _socket_ function is called to attempt to create a socket in the
stack. When the socket() API function is called the netstack table is
scanned and for each valid entry the _socket_ function is called. If
this returns non-zero then the scan continues to the next valid stack,
or terminates with an error if the end of the table is reached.

The result of a successful socket call is an initialized file object
with the _f_xops_ field pointing to the following structure:

struct cyg_sock_ops
{
    int (*bind)      ( cyg_file *fp, const sockaddr *sa, socklen_t len );
    int (*connect)   ( cyg_file *fp, const sockaddr *sa, socklen_t len );
    int (*accept)    ( cyg_file *fp, cyg_file *new_fp,
                       struct sockaddr *name, socklen_t *anamelen );
    int (*listen)    ( cyg_file *fp, int len );
    int (*getname)   ( cyg_file *fp, sockaddr *sa, socklen_t *len, int peer );
    int (*shutdown)  ( cyg_file *fp, int flags );
    int (*getsockopt)( cyg_file *fp, int level, int optname,
                       void *optval, socklen_t *optlen);
    int (*setsockopt)( cyg_file *fp, int level, int optname,
                       const void *optval, socklen_t optlen);
    int (*sendmsg)   ( cyg_file *fp, const struct msghdr *m,
                       int flags, ssize_t *retsize );
    int (*recvmsg)   ( cyg_file *fp, struct msghdr *m,
                       socklen_t *namelen, ssize_t *retsize );
};

It should be obvious from the names of these functions which API calls
they provide support for. The _getname_ function provides support for
both getsockname() and getpeername() while the _sendmsg_ and _recvmsg_
functions provide support for send(), sendto(), sendmsg(), recv(),
recvfrom() and recvmsg() as appropriate.



Select
------

The infrastructure provides support for implementing a select
mechanism. This is modeled on the mechanism in the BSD kernel, but has
been modified to make it implementation independent.

The main part of the mechanism is the select() API call. This
processes its arguments and calls the _fo_select_ function on all file
objects referenced by the file descriptor sets passed to it. If the
same descriptor appears in more than one descriptor set, the
_fo_select_ function will be called separately for each appearance.

The _which_ argument of the _fo_select_ function will either be
CYG_FREAD to test for read conditions, CYG_FWRITE to test for write
conditions or zero to test for exceptions. For each of these options
the function should test whether the condition is satisfied and if so
return true. If it is not satisfied then it should call
cyg_selrecord() with the _info_ argument that was passed to the
function and a pointer to a cyg_selinfo structure.

The cyg_selinfo structure is used to record information about current
select operations. Any object that needs to support select must
contain an instance of this structure.  Separate cyg_selinfo
structures should be kept for each of the options that the object can
select on - read, write or exception.

If none of the file objects report that the select condition is
satisfied, then the select() API function puts the calling thread to
sleep waiting either for a condition to become satisfied, or for the
optional timeout to expire.

A selectable object must have some asynchronous activity that may
cause a select condition to become true - either via interrupts or the
activities of other threads. Whenever a selectable condition is
satisfied, the object should call cyg_selwakeup() with a pointer to
the appropriate cyg_selinfo structure. If the thread is still waiting,
this will cause it to wake up and repeat its poll of the file
descriptors. This time around, the object that caused the wakeup
should indicate that the select condition is satisfied, and the
_select()_ API call will return.

Note that _select()_ does not exhibit real time behaviour: the
iterative poll of the descriptors, and the wakeup mechanism mitigate
against this. If real time response to device or socket I/O is
required then separate threads should be devoted to each device of
interest.


Devices
-------

Devices are accessed by means of a pseudo-filesystem, "devfs", that is
mounted on "/dev". Open operations are translated into calls to
cyg_io_lookup() and if successful result in a file object whose
_f_ops_ functions translate filesystem API functions into calls into
the device API.

// EOF fileio.txt

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -