|
|
// Copyright (C) 1999-2000 Open Source Telecom Corporation. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // // As a special exception to the GNU General Public License, permission is // granted for additional uses of the text contained in its release // of APE. // // The exception is that, if you link the APE library with other files // to produce an executable, this does not by itself cause the // resulting executable to be covered by the GNU General Public License. // Your use of that executable is in no way restricted on account of // linking the APE library code into it. // // This exception does not however invalidate any other reasons why // the executable file might be covered by the GNU General Public License. // // This exception applies only to the code released under the // name APE. If you copy code from other releases into a copy of // APE, as the General Public License permits, the exception does // not apply to the code that you add in this way. To avoid misleading // anyone as to the status of such modified files, you must delete // this exception notice from them. // // If you write modifications of your own for APE, it is your choice // whether to permit this exception to apply to your modifications. // If you do not wish that, delete this exception notice. #ifndef __APE_FILE_H__ #define __APE_FILE_H__ #ifndef __APE_THREAD_H__ #include <APE/thread.h> #endif #include <stdio.h> #include <fcntl.h> #include <sys/stat.h> #include <sys/mman.h> typedef unsigned long pos_t; enum { FILE_OPEN_READONLY = O_RDONLY, FILE_OPEN_WRITEONLY = O_WRONLY, FILE_OPEN_READWRITE = O_RDWR, FILE_OPEN_APPEND = O_WRONLY | O_APPEND, #ifdef O_SYNC FILE_OPEN_SYNC = O_RDWR | O_SYNC, #else FILE_OPEN_SYNC = O_RDWR, #endif FILE_OPEN_TRUNCATE = O_RDWR | O_TRUNC }; enum { FILE_MAPPED_READ = O_RDONLY, FILE_MAPPED_WRITE = O_WRONLY, FILE_MAPPED_RDWR = O_RDWR }; enum { FILE_PERM_PRIVATE = S_IRUSR | S_IWUSR, FILE_PERM_GROUP = FILE_PERM_PRIVATE | S_IRGRP | S_IWGRP, FILE_PERM_PUBLIC = FILE_PERM_GROUP | S_IROTH | S_IWOTH }; /** * The purpose of this class is to define a low level file access * class that is portable between Win32 and Posix systems. In fact * win32 lacks certain critical concepts related to multi-user file * ownership and yet introduces some very odd concepts of cache control * and configuration based on assumed application usage. These combine * to make this and the other related portable file access classes a * little odd, and certainly in need of further work. * * @author David Sugar <dyfet@ostel.com> * @short Portable disk file access. */ class File { protected: int _fd; public: /** * Open an existing file of the given name with the given access * mode. Valid access modes include FILE_OPEN_READONLY, FILE_OPEN_WRITEONLY, * FILE_OPEN_APPEND, FILE_OPEN_READWRITE, FILE_OPEN_SYNC, and FILE_OPEN_TRUNCATE. * A File "exception" is thrown if the file open fails. * * @param fname name of file path to open. * @param access mode for access to the given file. */ File(const char *fname, int access); /** * Create a new file and access for use by the File class. Valid modes * include FILE_OPEN_WRITEONLY, FILE_OPEN_APPEND, FILE_OPEN_SYNC, * and FILE_OPEN_READWRITE. The most generic permissions for your * newly created file include FILE_PERM_PRIVATE, FILE_PERM_GROUP, and * FILE_PERM_PUBIC. On Posix systems, the standard chmod() permission * values may be directly used, as well as the stat.h defines. As * with all APE classes, an exception is thrown if the create fails. * * @param fname name of file path to create and open. */ File(const char *fname, int access, int perm); /** * Open a copy of an existing "File" through a duplicate object. This * essentially uses the Posix dup() call to duplicate the file * descriptor involved. * * @param f an existing File class to duplicate from. */ File(const File &f); /** * Create a File "class" to reference an existing and already open * file descriptor. This is kind of like "fdopen" in purpose, and * simply allows any existing file descriptor to be manipulated * by the File methods. * * @param fd an existing and already open file descriptor. */ File(int fd); /** * The destructor normally closes the File descriptor and should * also release any allocated resources in a derived class. */ virtual ~File() {close(_fd);}; /** * Read an arbitrary number of bytes from the File object. * * @return number of bytes read with success, or -1 on error. * @param buf pointer to hold read data. * @param len number of bytes to read. */ int Read(void *buf, size_t len) {return read(_fd, (char *)buf, len);}; /** * Write an arbitrary number of bytes to the File object. * * @return number of bytes written on success, -1 on error. * @param buf pointer to data that will be written. * @param len number of butes to write. */ int Write(void *buf, size_t len) {return write(_fd, (char *)buf, len);}; /** * A quick and easy way to write a null terminated C string to * a file. * * @return number of bytes written on success, -1 on error. * @param pointer to null terminated string to write to the file. */ int Write(char *buf) {return write(_fd, buf, strlen(buf));}; /** * Set the current file position. This is an absolute position * from the start of the file. * * @return current file position after operation. * @param pos new file position to set file to. */ pos_t Position(pos_t pos) {return (pos_t)lseek(_fd, pos, SEEK_SET);}; /** * Set the current file position to the end of the file. * * @return file position (length) of the end of the file. */ pos_t Append(void) {return (pos_t)lseek(_fd, 0l, SEEK_END);}; File &operator=(const File &f); friend int read(File &f, void *buf, size_t len) {return read(f._fd, (char *)buf, len);}; friend int write(File &f, void *buf, size_t len) {return write(f._fd, (char *)buf, len);}; friend int write(File &f, char *buf) {return write(f._fd, buf, strlen(buf));}; friend pos_t append(File &f) {return (pos_t)lseek(f._fd, 0l, SEEK_END);}; friend pos_t position(File &f, pos_t pos) {return (pos_t)lseek(f._fd, pos, SEEK_SET);}; }; /** * Create a new file always on the specified path. If a file already * exists on the specified path name, it is removed. * * @author David Sugar <dyfet@ostel.com> * @short create a new file pathname. */ class NewFile : public File { protected: void Initial(char *fname, int perm) {remove(fname);}; public: NewFile(const char *fname, int access, int perms); }; /** * Create a new file as a FIFO device (named pipe) on the current * file system and then opens it. * * @author David Sugar <dyfet@ostel.com> * @short Create and open a named pipe. */ class NamedPipe : public File { protected: void Initial(char *fname, int perm); public: NamedPipe(const char *fname, int perms); }; /** * Create and map a disk file into memory. This portable class works * under both Posix via mmap and under the win32 API. A mapped file * can be referenced directly by it's memory segment. * * @author David Sugar * @short map a named disk file into memory. */ class MappedFile : protected File { private: size_t _len; char *_mem; public: /** * Map a portion or all of a specified file in the specified * shared memory access mode. Valid mapping modes include * FILE_MAPPED_READ, FILE_MAPPED_WRITE, and FILE_MAPPED_RDWR. * * @param fname pathname of file to map into memory. * @param offset from start of file to begin mapping in bytes. * @param size of mapped area in bytes. * @param mode to map file. */ MappedFile(const char *fname, pos_t offset, size_t size, int mode); /** * Release a mapped section of memory associated with a file. The * mapped area is updated back to disk. */ virtual ~MappedFile(); /** * Synchronize the contents of the mapped portion of memory with * the disk file and wait for completion. This assures the memory * mapped from the file is written back. */ inline void Sync(void) {msync(_mem, _len, MS_SYNC);}; /** * Map a portion of the memory mapped from the file back to the * file and do not wait for completion. This is useful when mapping * a database file and updating a single record. * * @param offset into the mapped region of memory. * @param len of partial region (example, record length). */ inline void Update(unsigned offset, size_t len) {msync(_mem + offset, len, MS_ASYNC);}; /** * Fetch a pointer to an offset within the memory mapped portion * of the disk file. This really is used for convience of matching * operations between Update and Fetch, as one could simply have * accessed the base pointer where the file was mapped directly. * * @param offset from start of mapped memory. */ inline void *Fetch(unsigned offset) {return _mem + offset;}; friend inline void sync(MappedFile &m) {msync(m._mem, m._len, MS_SYNC);}; friend inline void update(MappedFile &m, unsigned offset, size_t len) {msync(m._mem + offset, len, MS_ASYNC);}; friend inline void *fetch(MappedFile &m, unsigned offset = 0) {return m._mem + offset;}; }; /** * Locked files are presumed to be shared between different processes. * File locks are used to protect file access and specifically defined * operations which must occur exclusivily by a single process, such as * for logical record locks in a database. Record locking is assumed * to be a blocking operation. * * @author David Sugar <dyfet@ostel.com> * @short shared file access between different processes. */ class LockedFile : protected File { public: /** * Open an existing and named data file that may be shared by * multiple processes. Throw an exception if the file doesn't * exist or cannot be accessed. * * @param fname path name of disk file to open. * @param access access mode (read, write, or rdwr) to use. * @see File#File */ LockedFile(const char *fname, int access); /** * Duplicate an existing locked file's descriptor, but do not * duplicate any outstanding locks. * * @param f reference to another LockedFile. */ LockedFile(const LockedFile &f); /** * Release the locked file and any locks held by this object. */ ~LockedFile() {close(_fd);}; /** * Recieve a lock from the end of the current file to inf and * when successful write the specified data to the end. Upon * completion, release the file lock. * * @return number of bytes written on success, -1 on error. * @param buf pointer to data to write to the file. * @param len number of bytes to write. */ int Append(void *buf, size_t len); /** * Request a lock for a portion of the datafile and then read * the exclusivily locked portion of the file into memory. * * @return number of bytes read on success, -1 on error. * @param pos offset to portion of file to read. * @param buf pointer to memory to read data into. * @param len number of bytes to read. */ int Request(pos_t pos, void *buf, size_t len); /** * Copy a presumably modified memory block back to a locked * portion of a file as retrieved from a previous request, and * then clear the file lock so that another process may now * access that region. No check is made to assure the Update * actually matches a previous Request. * * @return number of bytes written on success, -1 on error. * @param pos offset to portion of file to write. * @param buf pointer to memory to write data from. * @param len number of bytes to write. */ int Update(pos_t pos, void *buf, size_t len); /** * Release a lock held from a request without modifying any * data in the file so that another process may now access the * locked region. No check is made to assure the Clear actually * matches an existing Request. * * @return 0 on success, -1 on error. * @param pos offset to portion of file that was locked. * @param len number of bytes originally requested. */ int Clear(pos_t pos, size_t len); }; /** * Locked files provide clean access to a database file that is shared * between multiple processes via file locking. A seperate and more * efficient methodology is provided here to enable multiple threads to * access the same file descriptor concurrently. While shared files do * not include thread exclusive file region locking, such locking can be * established with in memory based tables rather than kernel file locks * for speed if needed. * * @author David Sugar <dyfet@ostel.com> * @short Shared concurrent file access from multiple threads. */ class SharedFile : public File, public Mutex { public: /** * Create a new disk file that will be shared between multiple * threads. A file name, access mode, and file permissions to * use when creating a new file are specified. On failure an * exception is thrown. * * @param fname path name of disk file to open or create. * @param access file access mode. * @param perm file permission to assign when creating a new file. * @see File#File */ SharedFile(const char *fname, int access, int perm); /** * Open an existing disk file for shared access between multiple * threads. A file name and file access mode must be specified. * If the file does not exist or cannot be opened, an exception is * thrown. * * @param fname path name of disk file to open. * @param access file access mode. */ SharedFile(const char *fname, int access); /** * Open a copy of an existing "File" through a duplicate object for * shared access from multiple threads. This essentially uses the * Posix dup() call to duplicate the file descriptor involved. * * @param f an existing File class to duplicate from. */ SharedFile(const SharedFile &f); /** * Create a shared file "class" to reference an existing and already * open file descriptor from multiple threads. This is kind of like * "fdopen" in purpose, and simply allows any existing file descriptor * to be manipulated by the thread shared methods. * * @param fd an existing and already open file descriptor. */ SharedFile(int fd); /** * Close the existing shared file object and release any used * resources. */ ~SharedFile() {close(_fd);}; /** * Write data to the end of a specified share file exclusivily. * The mutex lock is used to assure the write operation is not * interfered with by other threads until it completes. * * @return number of bytes written on success, -1 on failure. * @param buf pointer to data to write to the file. * @param len number of bytes to write. */ int Append(void *buf, size_t len); /** * Read data from a specified file offset exclusivily. The Mutex * lock is used to assure the read operation can complete without * interference by other threads. While the current file offset * must be specified and tracked seperately by each thread on it's * own, an enhanced version may soon use a ThreadKey for this purpose. * * @return number of bytes read on success, -1 on error. * @param pos file offset to start read from file. * @param buf pointer to store data read from file. * @param len number of bytes to read. */ int Read(pos_t pos, void *buf, size_t len); /** * Write data to a specified file offset exclusivily. The Mutex * lock is used to assure the write operation can complete without * interference by other threads. While the current file offset * must be specified and tracked seperately by each thread on it's * own, an enhanced version may soon use a ThreadKey for this purpose. * * @return number of bytes written on success, -1 on error. * @param pos file offset to start file write. * @param buf pointer to data to write to the file. * @param len number of bytes to write. */ int Write(pos_t pos, void *buf, size_t len); SharedFile &operator=(SharedFile &f); friend inline int read(SharedFile &f, pos_t pos, void *buf, size_t len) {return f.Read(pos, buf, len);}; friend inline int write(SharedFile &f, pos_t pos, void *buf, size_t len) {return f.Write(pos, buf, len);}; friend inline int append(SharedFile &f, void *buf, size_t len) {return f.Append(buf, len);}; }; /** * The Pipe uses system kernel buffering to hold data being passed either * between two execution contexts within the same process, or between * different processes. Unlike thread's "Buffer", Pipe uses system * descriptors and kernel memory. Under Posix, the size of the pipe and * associated kernel memory is always a fixed constant as defined by * _PC_PIPE_BUF. The APE "pipe" class primarily deals with "atomic" * transfers of fixed sized objects through pipes. Pipes may pass * data arbitrarily and can also be used through the "pipestream" class. * * The "Pipe" class is not meant to be a true "public" class, but as a * builder class for deriving other classes. * * @author David Sugar <dyfet@ostel.com>. * @short kernel buffering between processes and/or threads. */ class Pipe { private: int fd[2]; int objcount; int objsize; protected: /** * Get the object size for atomic operations. * * @return size of atomic operations. */ inline int getSize(void) {return objsize;}; /** * Sender is often used for implementing a fork()'d message port * between processes. By stopping the sender, the current pipe * can then only be used for receiving, and the sender is presumed * to be in the other half of a fork()'d process. * * @see #endReceiver */ inline void endSender(void) {close(fd[1]);}; /** * Receiver is often used for implementing a fork()'d message port * between processes. By stopping the receiver, the current pipe * can then only be used for sending, and the receiver is presumed * to be in the other half of a fork()'d process. * * @see #endSender */ inline void endReceiver(void) {close(fd[0]);}; /** * Create a kernel pipe descriptor set using pipe(). On systems * which allow the pipe kernel buffer to be defined, a size for * aligned atomic transfers can be set, as well as the number of * atomic objects the kernel will buffer. On Posix systems, these * options are ignored. * * @param objsize of atomic objects to send. * @param count of atomic objects to kernel buffer. */ Pipe(int size = 512, int count = 1); /** * Destroy the pipe and kernel descriptor resources. */ ~Pipe(); /** * Create a pipe as a duplicate of an existing pipe. * * @param orig pipe to duplicate. */ Pipe(const Pipe &orig); Pipe &operator=(const Pipe &orig); public: /** * Used to see if the pipe has any open entities. */ bool operator!(); /** * Perform an object atomic transfer of data from a pipe. * * @return number of bytes actually read if successful. * @param addr pointer to store read data. * @param len number of bytes to read. */ inline int Recv(void *addr) {return ::read(fd[0], (char *)addr, objsize);}; /** * Perform an object atomic transfer of data to a pipe. * * @return number of bytes written if successful. * @param addr pointer to write data from. * @param len number of butes to write. */ inline int Send(void *addr) {return ::write(fd[1], (char *)addr, objsize);}; }; /** * The DSO dynamic loader class is used to load object files. On * elf based systems this is typically done with dlopen. A dummy * stub class is generated for non-dl capable systems. * * @author David Sugar <dyfet@ostel.com> * @short Dynamic class file loader. */ class DSO { private: #ifdef HAVE_MODULES static Mutex mutex; static DSO *first, *last; DSO *next, *prev; void *image; #endif public: /** * Construct and load a DSO object file. * * @param pathname of object file to load. */ #ifdef HAVE_MODULES DSO(char *filename); #else DSO(char *filename) {throw this;}; #endif /** * Detach a DSO object from running memory. */ #ifdef HAVE_MODULES ~DSO(); #endif /** * Lookup a symbol in the loaded file. */ #ifdef HAVE_MODULES void *operator[](const char *); #else void *operator[](const char *) {return NULL;}; #endif #ifdef HAVE_MODULES friend void dynunload(void); #else friend void dynunload(void) {return;}; #endif }; inline int clear(LockedFile &f, pos_t pos, size_t len) {return f.Clear(pos, len);}; inline int append(LockedFile &f, void *buf, size_t len) {return f.Append(buf, len);}; inline int request(LockedFile &f, pos_t pos, void *buf, size_t len) {return f.Request(pos, buf, len);}; inline int update(LockedFile &f, pos_t pos, void *buf, size_t len) {return f.Update(pos, buf, len);}; #endif
Generated by: dyfet@home.sys on Tue Mar 7 09:18:03 200. |