
|
[openbeosstorage]
||
[Date Prev]
[02-2002 Date Index]
[Date Next]
||
[Thread Prev]
[02-2002 Thread Index]
[Thread Next]
[openbeosstorage] Re: Kernel Interface Design
- From: Keith Poole <keef@xxxxxxxxxxxxxxx>
- To: openbeosstorage@xxxxxxxxxxxxx
- Date: Tue, 12 Feb 2002 00:36:14 +0000
My attempt at the emulator code (haven't had chance to try it under BeOS
yet - but it compiles under gcc). Any comments on this one?
I think Tyler's right about throwing exceptions - this version doesn't,
but it would make the code clearer if it did.
Data types - open modes are ints if you use open rather than fopen
(O_CREAT, etc) - see the attached example
Keith
Tyler Dauwalder wrote:
>Hey folks,
>
>Sorry for being a bit quiet over the past couple of days; I
>went to visit my mom over the weekend and got absolutely
>nothing done whatsoever.
>
>I think it's time we started planning out what I'm going to
>from here out refer to as our "kernel interface". By that I
>mean our bottom-level C functions that we'll initially implement
>with POSIX and later implement with syscalls.
>
>(one short note here: I'm calling them C functions, but I
>don't see any reason we would be restricted to using pure C)
>
>I made up a quick header and cpp pair with rough POSIX
>implementations of open() and close() to try and get a sense
>of some of the issues we're going to need to address in our
>design. There in CVS at:
>
>/storage_kit/source/lib/kernel_interface.h
>/storage_kit/source/lib/kernel_interface.POSIX.cpp
>
>Please note that I haven't tried compiling these, I just
>needed a place to start.
>
>
>----------------------------------------------------------------------
>1. Interface portability
>----------------------------------------------------------------------
>
>First and formost, we want to design our interface to be
>as portable as possible, meaning we don't want it to work
>fine with POSIX but then have to be changed when we
>rewrite it to use syscalls. To that degree, I've started a
>brief function dependency document in CVS at:
>
>/storage_kit/docs/kernel_interface/FunctionDependencyReference.html
>
>All I've done is list the NewOS and POSIX calls that each function
>will depend on. This helps to give a sense of how each function will
>need to be designed in order for it to work as an interface to both
>the kernel and POSIX.
>
>For calls that are not yet implemented in the kernel, we're
>just going to have to make educated guesses based on
>the calls that *are* implemented.
>
>One thing I'd like everybody to do is just pick a few functions,
>look up the user_* equivalent in the NewOS kernel (vfs.h) or
>extrapolate a reasonable guess as to what it might look like if
>it doesn't exist, figure out which POSIX functions and headers
>are involved, and add said info to the list.
>
>As I've mentioned before, the set of functions in our interface will
>need to be basically identical to the set of functions in the vfs add-on
>layer we documented. So use that list of functions as a base for
>which functions we need to have in our interface that aren't currently
>supported in the kernel.
>
>I guess just pick a few functions at a time, email the list saying
>you're going to work on those, and do your thing. There are templates
>in comments in the HTML file for the various sections you'll need
>to update.
>
>
>----------------------------------------------------------------------
>2. Error handling
>----------------------------------------------------------------------
>
>We're going to want/need a uniform method of error handling.
>We can either use exceptions or something depending on
>return values and/or output parameters. My vote's for exceptions
>unless someone thinks that's a really bad idea.
>
>
>----------------------------------------------------------------------
>3. Data types
>----------------------------------------------------------------------
>
>There's not a lot of consistency between POSIX and the kernel API
>as far as data types go. For example, open modes in POSIX are
>character strings, but in the kernel they're ints. I propose we create
>our own set of data types as needed specifically for this interface.
>These will end up being the data types we use throughout the entire
>Storage Kit, and I think having a well thought out set of types to work
>with will make our job easier and make our code cleaner.
>
>In some cases, we're not going to be able or want to change
>data structures around too much. There's proabably no good
>reason for a file descriptor to be anything but an int. Directory
>functions are probably going to work with dirents. In other cases,
>like open modes, defining our own enum of values will probably
>be useful.
>
>I'm also thinking it might eventually be a good idea to go through
>the Storage Kit and make up a dependency reference similar to
>the one for the kernel interface. Something a little more in depth
>that lists off the kind of functionality each class provides and what
>sorts of data types it will need to sling around in order to accomplish
>what it's supposed to accomplish. We don't need to jump on that
>just yet though.
>
>
>
>I think those are the main issues I wanted to address (it's really late,
>so I may have overlooked some...). Look through the kernel_interface.*
>code and see what you think of the examples in there, and write up
>a couple of dependencies as you're able. :-)
>
>-Tyler
>
>
>
>
>
>
-- Attached file included as plaintext by Listar --
-- File: kernel_interface.POSIX.cpp
//----------------------------------------------------------------------
// kernel_interface.POSIX.cpp
// Initial implementation of our kernel interface with calls to
// POSIX api. This will later be replaced with a version that
// makes syscalls into the actual kernel
//----------------------------------------------------------------------
#include "kernel_interface.h"
#include <fcntl.h>
#include <dirent.h>
#include <unistd.h>
typedef struct {
stream_type st;
DIR* dir;
int file;
} fd_struct;
const int MAX_DESC = 256;
static fd_struct our_fds[MAX_DESC];
static int highest_fd = -1;
// The following two functions allocate and free file descriptors
// to make this emulation layer thread safe, they should have
// some kind of semaphore around them.
static int storage_kit::alloc_fd()
{
// Allocate a file descriptor
for (int i = 0; i < highest_fd; i++) {
if (our_fds[i].st == STREAM_TYPE_ANY) {
// Free one - use it
return i;
}
}
// Fell through = use next in list
if (highest_fd < MAX_DESC) {
return ++highest_fd;
} else {
return ERR_VFS_FD_TABLE_FULL; // or throw
}
}
static void storage_kit::free_fd(int fd)
{
our_fds[fd].st = STREAM_TYPE_ANY;
}
// End of thread unsafe code
int storage_kit::open(const char *path, stream_type st, int omode)
{
// Open a file or directory
int fd = storage_kit::alloc_fd();
if (fd >= 0) {
// Which type of stream are we opening?
switch (st) {
case STREAM_TYPE_ANY:
case STREAM_TYPE_DEVICE:
default:
storage_kit::free_fd(fd);
fd = ERR_VFS_WRONG_STREAM_TYPE;
break;
case STREAM_TYPE_FILE:
our_fds[fd].st = st;
our_fds[fd].file = ::open(path, omode, 0777);
if (our_fds[fd].file < 0) {
storage_kit::free_fd(fd);
fd = ERR_VFS_PATH_NOT_FOUND; //
Dodgy code
}
break;
case STREAM_TYPE_DIR:
our_fds[fd].st = st;
our_fds[fd].dir = ::opendir(path);
if (our_fds[fd].dir == NULL) {
storage_kit::free_fd(fd);
fd = ERR_VFS_PATH_NOT_FOUND; // Only
error in posix docs
}
break;
}
}
return fd;
}
int storage_kit::close(int fd)
{
// Which type of stream are we opening?
int err = NO_ERROR;
switch (our_fds[fd].st) {
case STREAM_TYPE_ANY:
case STREAM_TYPE_DEVICE:
default:
return ERR_VFS_INVALID_FS; // fd table corruption!
case STREAM_TYPE_FILE:
if(::close(our_fds[fd].file) < 0) {
err = ERR_VFS_INVALID_FS;
}
break;
case STREAM_TYPE_DIR:
::closedir(our_fds[fd].dir);
break;
}
return fd;
}
size_t storage_kit::read(int fd, void *buf, off_t pos, ssize_t len)
{
// Get some data frm a file (or directory)
int err = NO_ERROR;
size_t data_read;
switch (our_fds[fd].st) {
case STREAM_TYPE_ANY:
case STREAM_TYPE_DEVICE:
default:
return ERR_VFS_INVALID_FS; // fd table corruption!
case STREAM_TYPE_FILE:
if(pos < 0) {
// Use current position
data_read = ::read(our_fds[fd].file, buf, len);
} else {
// Positional read
::lseek(our_fds[fd].file, pos, SEEK_CUR);
data_read = ::read(our_fds[fd].file, buf, len);
}
break;
case STREAM_TYPE_DIR:
struct dirent *dp = ::readdir(our_fds[fd].dir);
if (dp == NULL) {
data_read = 0;
} else {
if (strlen(dp->d_name) > len) {
// Not enough room
*((char*)buf) = '\0';
data_read = ERR_VFS_INSUFFICIENT_BUF;
} else {
strcpy((char*)buf, dp->d_name);
data_read = strlen(dp->d_name);
}
}
break;
}
return data_read;
}
-- Attached file included as plaintext by Listar --
-- File: kernel_interface.h
//----------------------------------------------------------------------
// kernel_interface.h
// This is the internal interface used by the storage kit to
// communicate with the kernel
//----------------------------------------------------------------------
#ifndef _sk_kernel_interface_h_
#define _sk_kernel_interface_h_
//#include <SupportKit.h>
#include <sys/types.h>
#include <sys/stat.h>
// stolen from the NewOS kernel
typedef enum {
STREAM_TYPE_ANY = 0,
STREAM_TYPE_FILE,
STREAM_TYPE_DIR,
STREAM_TYPE_DEVICE
} stream_type;
typedef enum {
SEEK_SET = 0,
SEEK_CUR,
SEEK_END
} seek_type;
/* VFS errors */
#define ERR_VFS_GENERAL -3072
#define ERR_VFS_INVALID_FS ERR_VFS_GENERAL-1
#define ERR_VFS_NOT_MOUNTPOINT ERR_VFS_GENERAL-2
#define ERR_VFS_PATH_NOT_FOUND ERR_VFS_GENERAL-3
#define ERR_VFS_INSUFFICIENT_BUF ERR_VFS_GENERAL-4
#define ERR_VFS_READONLY_FS ERR_VFS_GENERAL-5
#define ERR_VFS_ALREADY_EXISTS ERR_VFS_GENERAL-6
#define ERR_VFS_FS_BUSY ERR_VFS_GENERAL-7
#define ERR_VFS_FD_TABLE_FULL ERR_VFS_GENERAL-8
#define ERR_VFS_CROSS_FS_RENAME ERR_VFS_GENERAL-9
#define ERR_VFS_DIR_NOT_EMPTY ERR_VFS_GENERAL-10
#define ERR_VFS_NOT_DIR ERR_VFS_GENERAL-11
#define ERR_VFS_WRONG_STREAM_TYPE ERR_VFS_GENERAL-12
#define ERR_VFS_ALREADY_MOUNTPOINT ERR_VFS_GENERAL-13
/* General errors */
#define NO_ERROR 0
#define ERR_GENERAL -1
#define ERR_NO_MEMORY ERR_GENERAL-1
#define ERR_IO_ERROR ERR_GENERAL-2
#define ERR_INVALID_ARGS ERR_GENERAL-3
#define ERR_TIMED_OUT ERR_GENERAL-4
#define ERR_NOT_ALLOWED ERR_GENERAL-5
#define ERR_PERMISSION_DENIED ERR_GENERAL-6
#define ERR_INVALID_BINARY ERR_GENERAL-7
#define ERR_INVALID_HANDLE ERR_GENERAL-8
#define ERR_NO_MORE_HANDLES ERR_GENERAL-9
#define ERR_UNIMPLEMENTED ERR_GENERAL-10
#define ERR_TOO_BIG ERR_GENERAL-11
#define ERR_NOT_FOUND ERR_GENERAL-12
#define ERR_NOT_IMPLEMENTED_YET ERR_GENERAL-13
#define ERR_NOMORE_HANDLES ERR_GENERAL-14
//----------------------------------------------------------------------
// user_* functions pulled from NewOS's vfs.h (with the "user_" part removed)
//----------------------------------------------------------------------
//int mount(const char *path, const char *device, const char *fs_name, void
*args);
//int unmount(const char *path);
//int sync(void);
//int open(const char *path, stream_type st, int omode);
//int close(int fd);
//int fsync(int fd);
//ssize_t read(int fd, void *buf, off_t pos, ssize_t len);
//ssize_t write(int fd, const void *buf, off_t pos, ssize_t len);
//int seek(int fd, off_t pos, seek_type seek_type);
//int ioctl(int fd, int op, void *buf, size_t len);
//int create(const char *path, stream_type stream_type);
//int unlink(const char *path);
//int rename(const char *oldpath, const char *newpath);
//int rstat(const char *path, struct file_stat *stat);
//int wstat(const char *path, struct file_stat *stat, int stat_mask);
//int getcwd(char *buf, size_t size);
//int setcwd(const char* path);
//int dup(int fd);
//int dup2(int ofd, int nfd);
//----------------------------------------------------------------------
namespace storage_kit {
int open(const char *path, stream_type st, int omode);
int close(int fd);
size_t read(int fd, void *buf, off_t pos, ssize_t len);
size_t write(int fd, const void *buf, off_t pos, ssize_t len);
int alloc_fd();
void free_fd(int fd);
}
#endif
|

|