From e2324c081a4b1a0c6d7fdaaa99e0d5ef29325e20 Mon Sep 17 00:00:00 2001 From: Joel Sherrill Date: Tue, 14 Oct 2008 15:06:25 +0000 Subject: 2008-10-14 Wei Shen * Makefile.am, preinstall.am, libcsupport/src/mknod.c, libcsupport/src/open.c, libcsupport/src/pipe.c, libfs/Makefile.am, libfs/preinstall.am, libfs/src/imfs/imfs.h, libfs/src/imfs/imfs_creat.c, libfs/src/imfs/imfs_debug.c, libfs/src/imfs/imfs_eval.c, libfs/src/imfs/imfs_initsupp.c, libfs/src/imfs/imfs_mknod.c, libfs/src/imfs/imfs_stat.c, libfs/src/imfs/memfile.c: Initial commit of POSIX pipe support. * libfs/src/imfs/imfs_fifo.c, libfs/src/pipe/fifo.c, libfs/src/pipe/pipe.c, libfs/src/pipe/pipe.h: New files. --- cpukit/libfs/Makefile.am | 7 +- cpukit/libfs/preinstall.am | 2 + cpukit/libfs/src/imfs/imfs.h | 17 +- cpukit/libfs/src/imfs/imfs_creat.c | 4 + cpukit/libfs/src/imfs/imfs_debug.c | 5 + cpukit/libfs/src/imfs/imfs_eval.c | 3 + cpukit/libfs/src/imfs/imfs_fifo.c | 151 ++++++++++ cpukit/libfs/src/imfs/imfs_initsupp.c | 11 +- cpukit/libfs/src/imfs/imfs_mknod.c | 5 +- cpukit/libfs/src/imfs/imfs_stat.c | 4 + cpukit/libfs/src/imfs/memfile.c | 2 +- cpukit/libfs/src/pipe/fifo.c | 551 ++++++++++++++++++++++++++++++++++ cpukit/libfs/src/pipe/pipe.c | 83 +++++ cpukit/libfs/src/pipe/pipe.h | 113 +++++++ 14 files changed, 947 insertions(+), 11 deletions(-) create mode 100644 cpukit/libfs/src/imfs/imfs_fifo.c create mode 100644 cpukit/libfs/src/pipe/fifo.c create mode 100644 cpukit/libfs/src/pipe/pipe.c create mode 100644 cpukit/libfs/src/pipe/pipe.h (limited to 'cpukit/libfs') diff --git a/cpukit/libfs/Makefile.am b/cpukit/libfs/Makefile.am index 1b907a46dd..a5a2537ff0 100644 --- a/cpukit/libfs/Makefile.am +++ b/cpukit/libfs/Makefile.am @@ -28,7 +28,7 @@ libimfs_a_SOURCES += src/imfs/imfs_chown.c src/imfs/imfs_config.c \ src/imfs/imfs_mknod.c src/imfs/imfs_mount.c src/imfs/imfs_fchmod.c \ src/imfs/imfs_unlink.c src/imfs/imfs_unmount.c src/imfs/imfs_utime.c \ src/imfs/imfs_ntype.c src/imfs/imfs_stat.c src/imfs/imfs_getchild.c \ - src/imfs/memfile.c src/imfs/deviceio.c \ + src/imfs/memfile.c src/imfs/imfs_fifo.c src/imfs/deviceio.c \ src/imfs/imfs_handlers_device.c src/imfs/imfs_handlers_directory.c \ src/imfs/imfs_handlers_link.c src/imfs/imfs_handlers_memfile.c \ src/imfs/imfs_debug.c src/imfs/imfs_rmnod.c src/imfs/imfs_symlink.c \ @@ -43,6 +43,11 @@ libimfs_a_SOURCES += src/imfs/imfs_chown.c src/imfs/imfs_config.c \ src/devfs/devfs.h endif +# POSIX FIFO/pipe +if ! UNIX +libimfs_a_SOURCES += src/pipe/fifo.c src/pipe/pipe.c src/pipe/pipe.h +endif + # dosfs if LIBDOSFS diff --git a/cpukit/libfs/preinstall.am b/cpukit/libfs/preinstall.am index dba6cc4d81..7bccdb3872 100644 --- a/cpukit/libfs/preinstall.am +++ b/cpukit/libfs/preinstall.am @@ -5,3 +5,5 @@ $(srcdir)/preinstall.am: Makefile.am $(AMPOLISH3) $(srcdir)/Makefile.am > $(srcdir)/preinstall.am endif +if ! UNIX +endif diff --git a/cpukit/libfs/src/imfs/imfs.h b/cpukit/libfs/src/imfs/imfs.h index bd56bd57f4..b53a3cd8b4 100644 --- a/cpukit/libfs/src/imfs/imfs.h +++ b/cpukit/libfs/src/imfs/imfs.h @@ -25,6 +25,8 @@ extern "C" { #include #include +#include + /* * File name macros */ @@ -59,6 +61,10 @@ typedef struct { char *name; } IMFS_sym_link_t; +typedef struct { + pipe_control_t *pipe; +} IMFS_fifo_t; + /* * IMFS "memfile" information * @@ -84,7 +90,7 @@ typedef struct { extern int imfs_rq_memfile_bytes_per_block; extern int imfs_memfile_bytes_per_block; -#define IMFS_MEMFILE_BYTES_PER_BLOCK imfs_memfile_bytes_per_block +#define IMFS_MEMFILE_BYTES_PER_BLOCK imfs_memfile_bytes_per_block #define IMFS_MEMFILE_BLOCK_SLOTS \ (IMFS_MEMFILE_BYTES_PER_BLOCK / sizeof(void *)) @@ -135,8 +141,9 @@ typedef struct { #define IMFS_SYM_LINK RTEMS_FILESYSTEM_SYM_LINK #define IMFS_MEMORY_FILE RTEMS_FILESYSTEM_MEMORY_FILE #define IMFS_LINEAR_FILE (IMFS_MEMORY_FILE + 1) +#define IMFS_FIFO (IMFS_LINEAR_FILE + 1) -#define IMFS_NUMBER_OF_TYPES (IMFS_LINEAR_FILE + 1) +#define IMFS_NUMBER_OF_TYPES (IMFS_FIFO + 1) typedef union { IMFS_directory_t directory; @@ -145,6 +152,7 @@ typedef union { IMFS_sym_link_t sym_link; IMFS_memfile_t file; IMFS_linearfile_t linearfile; + IMFS_fifo_t fifo; } IMFS_types_union; /* @@ -196,12 +204,12 @@ struct IMFS_jnode_tt { _jnode->stat_ctime = (time_t) tv.tv_sec; \ } while (0) -#define IMFS_atime_mtime_update( _jnode ) \ +#define IMFS_mtime_ctime_update( _jnode ) \ do { \ struct timeval tv; \ gettimeofday( &tv, 0 ); \ _jnode->stat_mtime = (time_t) tv.tv_sec; \ - _jnode->stat_atime = (time_t) tv.tv_sec; \ + _jnode->stat_ctime = (time_t) tv.tv_sec; \ } while (0) typedef struct { @@ -230,6 +238,7 @@ extern const rtems_filesystem_file_handlers_r IMFS_directory_handlers; extern const rtems_filesystem_file_handlers_r IMFS_device_handlers; extern const rtems_filesystem_file_handlers_r IMFS_link_handlers; extern const rtems_filesystem_file_handlers_r IMFS_memfile_handlers; +extern const rtems_filesystem_file_handlers_r IMFS_fifo_handlers; extern const rtems_filesystem_operations_table IMFS_ops; extern const rtems_filesystem_operations_table miniIMFS_ops; extern const rtems_filesystem_limits_and_options_t IMFS_LIMITS_AND_OPTIONS; diff --git a/cpukit/libfs/src/imfs/imfs_creat.c b/cpukit/libfs/src/imfs/imfs_creat.c index ccf88bdf64..946e71d729 100644 --- a/cpukit/libfs/src/imfs/imfs_creat.c +++ b/cpukit/libfs/src/imfs/imfs_creat.c @@ -112,6 +112,10 @@ IMFS_jnode_t *IMFS_create_node( node->info.file.triply_indirect = 0; break; + case IMFS_FIFO: + node->info.fifo.pipe = NULL; + break; + default: assert(0); break; diff --git a/cpukit/libfs/src/imfs/imfs_debug.c b/cpukit/libfs/src/imfs/imfs_debug.c index d766c5e8b1..eb7541bb6a 100644 --- a/cpukit/libfs/src/imfs/imfs_debug.c +++ b/cpukit/libfs/src/imfs/imfs_debug.c @@ -98,6 +98,11 @@ void IMFS_print_jnode( assert(0); break; + case IMFS_FIFO: + fprintf(stdout, " FIFO not printed\n" ); + assert(0); + break; + default: fprintf(stdout, " bad type %d\n", the_jnode->type ); assert(0); diff --git a/cpukit/libfs/src/imfs/imfs_eval.c b/cpukit/libfs/src/imfs/imfs_eval.c index 9d8328d3a5..8c72fca049 100644 --- a/cpukit/libfs/src/imfs/imfs_eval.c +++ b/cpukit/libfs/src/imfs/imfs_eval.c @@ -57,6 +57,9 @@ int IMFS_Set_handlers( case IMFS_MEMORY_FILE: loc->handlers = fs_info->memfile_handlers; break; + case IMFS_FIFO: + loc->handlers = &IMFS_fifo_handlers; + break; } return 0; diff --git a/cpukit/libfs/src/imfs/imfs_fifo.c b/cpukit/libfs/src/imfs/imfs_fifo.c new file mode 100644 index 0000000000..97fef98db6 --- /dev/null +++ b/cpukit/libfs/src/imfs/imfs_fifo.c @@ -0,0 +1,151 @@ +/* + * imfs_fifo.c: FIFO support for IMFS + * + * Author: Wei Shen + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#include "imfs.h" + +#define JNODE2PIPE(_jnode) ( (_jnode)->info.fifo.pipe ) + +#define LIBIO2PIPE(_iop) ( JNODE2PIPE((IMFS_jnode_t *)(_iop)->file_info) ) + +/* Set errno and return -1 if error, else return _err */ +#define IMFS_FIFO_RETURN(_err) \ +do { \ + if (_err < 0) \ + rtems_set_errno_and_return_minus_one(-_err); \ + return _err; \ +} while (0) + +int IMFS_fifo_open( + rtems_libio_t *iop, + const char *pathname, + uint32_t flag, + uint32_t mode +) +{ + IMFS_jnode_t *jnode = iop->file_info; + + int err = fifo_open(&JNODE2PIPE(jnode), iop); + IMFS_FIFO_RETURN(err); +} + +int IMFS_fifo_close( + rtems_libio_t *iop +) +{ + IMFS_jnode_t *jnode = iop->file_info; + + int err = pipe_release(&JNODE2PIPE(jnode), iop); + + if (! err) { + iop->flags &= ~LIBIO_FLAGS_OPEN; + /* Free jnode if file is already unlinked and no one opens it */ + if (! rtems_libio_is_file_open(jnode) && jnode->st_nlink < 1) + free(jnode); + } + + IMFS_FIFO_RETURN(err); +} + +ssize_t IMFS_fifo_read( + rtems_libio_t *iop, + void *buffer, + size_t count +) +{ + IMFS_jnode_t *jnode = iop->file_info; + + int err = pipe_read(JNODE2PIPE(jnode), buffer, count, iop); + if (err > 0) + IMFS_update_atime(jnode); + + IMFS_FIFO_RETURN(err); +} + +ssize_t IMFS_fifo_write( + rtems_libio_t *iop, + const void *buffer, + size_t count +) +{ + IMFS_jnode_t *jnode = iop->file_info; + + int err = pipe_write(JNODE2PIPE(jnode), buffer, count, iop); + if (err > 0) { + IMFS_mtime_ctime_update(jnode); + } + + IMFS_FIFO_RETURN(err); +} + +int IMFS_fifo_ioctl( + rtems_libio_t *iop, + uint32_t command, + void *buffer +) +{ + int err; + + if (command == FIONBIO) { + if (buffer == NULL) + err = -EFAULT; + else { + if (*(int *)buffer) + iop->flags |= LIBIO_FLAGS_NO_DELAY; + else + iop->flags &= ~LIBIO_FLAGS_NO_DELAY; + return 0; + } + } + else + err = pipe_ioctl(LIBIO2PIPE(iop), command, buffer, iop); + + IMFS_FIFO_RETURN(err); +} + +int IMFS_fifo_lseek( + rtems_libio_t *iop, + off_t offset, + int whence +) +{ + int err = pipe_lseek(LIBIO2PIPE(iop), offset, whence, iop); + IMFS_FIFO_RETURN(err); +} + +/* + * Handler table for IMFS FIFO nodes + */ + +const rtems_filesystem_file_handlers_r IMFS_fifo_handlers = { + IMFS_fifo_open, + IMFS_fifo_close, + IMFS_fifo_read, + IMFS_fifo_write, + IMFS_fifo_ioctl, + IMFS_fifo_lseek, + IMFS_stat, + IMFS_fchmod, + NULL, /* ftruncate */ + NULL, /* fpathconf */ + NULL, /* fsync */ + NULL, /* fdatasync */ + IMFS_fcntl, + IMFS_rmnod, +}; diff --git a/cpukit/libfs/src/imfs/imfs_initsupp.c b/cpukit/libfs/src/imfs/imfs_initsupp.c index 62d6b11c7a..648150257b 100644 --- a/cpukit/libfs/src/imfs/imfs_initsupp.c +++ b/cpukit/libfs/src/imfs/imfs_initsupp.c @@ -47,17 +47,17 @@ static int IMFS_determine_bytes_per_block( * check, whether requested bytes per block is valid */ for (bit_mask = 16; - !is_valid && (bit_mask <= 512); + !is_valid && (bit_mask <= 512); bit_mask <<= 1) { if (bit_mask == requested_bytes_per_block) { is_valid = true; } } - *dest_bytes_per_block = ((is_valid) + *dest_bytes_per_block = ((is_valid) ? requested_bytes_per_block : default_bytes_per_block); return 0; - + } @@ -81,7 +81,7 @@ int IMFS_initialize_support( IMFS_determine_bytes_per_block(&imfs_memfile_bytes_per_block, imfs_rq_memfile_bytes_per_block, IMFS_MEMFILE_DEFAULT_BYTES_PER_BLOCK); - + /* * Create the root node * @@ -121,5 +121,8 @@ int IMFS_initialize_support( jnode = temp_mt_entry->mt_fs_root.node_access; jnode->st_ino = fs_info->ino_count; + /* Initialize POSIX FIFO/pipe module */ + rtems_pipe_initialize(); + return 0; } diff --git a/cpukit/libfs/src/imfs/imfs_mknod.c b/cpukit/libfs/src/imfs/imfs_mknod.c index abb9ab4052..9d35e61922 100644 --- a/cpukit/libfs/src/imfs/imfs_mknod.c +++ b/cpukit/libfs/src/imfs/imfs_mknod.c @@ -54,7 +54,10 @@ int IMFS_mknod( else if ( S_ISBLK(mode) || S_ISCHR(mode) ) { type = IMFS_DEVICE; rtems_filesystem_split_dev_t( dev, info.device.major, info.device.minor ); - } else { + } + else if (S_ISFIFO(mode)) + type = IMFS_FIFO; + else { rtems_set_errno_and_return_minus_one( EINVAL ); } diff --git a/cpukit/libfs/src/imfs/imfs_stat.c b/cpukit/libfs/src/imfs/imfs_stat.c index 422e954ed1..76564811e9 100644 --- a/cpukit/libfs/src/imfs/imfs_stat.c +++ b/cpukit/libfs/src/imfs/imfs_stat.c @@ -49,6 +49,10 @@ int IMFS_stat( buf->st_size = 0; break; + case IMFS_FIFO: + buf->st_size = 0; + break; + default: rtems_set_errno_and_return_minus_one( ENOTSUP ); break; diff --git a/cpukit/libfs/src/imfs/memfile.c b/cpukit/libfs/src/imfs/memfile.c index 2391373acb..a0a89f64ec 100644 --- a/cpukit/libfs/src/imfs/memfile.c +++ b/cpukit/libfs/src/imfs/memfile.c @@ -844,7 +844,7 @@ fprintf(stdout, "write %d in %d: %*s\n", to_copy, block, to_copy, src ); copied += to_copy; } - IMFS_atime_mtime_update( the_jnode ); + IMFS_mtime_ctime_update( the_jnode ); return copied; } diff --git a/cpukit/libfs/src/pipe/fifo.c b/cpukit/libfs/src/pipe/fifo.c new file mode 100644 index 0000000000..1c194c2030 --- /dev/null +++ b/cpukit/libfs/src/pipe/fifo.c @@ -0,0 +1,551 @@ +/* + * fifo.c: POSIX FIFO/pipe for RTEMS + * + * Author: Wei Shen + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#include +#include +#include "pipe.h" + + +#define MIN(a, b) ((a) < (b)? (a): (b)) + +#define LIBIO_ACCMODE(_iop) ((_iop)->flags & LIBIO_FLAGS_READ_WRITE) +#define LIBIO_NODELAY(_iop) ((_iop)->flags & LIBIO_FLAGS_NO_DELAY) + +extern uint16_t rtems_pipe_no; +static rtems_id rtems_pipe_semaphore = 0; + + +#define PIPE_EMPTY(_pipe) (_pipe->Length == 0) +#define PIPE_FULL(_pipe) (_pipe->Length == _pipe->Size) +#define PIPE_SPACE(_pipe) (_pipe->Size - _pipe->Length) +#define PIPE_WSTART(_pipe) ((_pipe->Start + _pipe->Length) % _pipe->Size) + +#define PIPE_LOCK(_pipe) \ + ( rtems_semaphore_obtain(_pipe->Semaphore, RTEMS_WAIT, RTEMS_NO_TIMEOUT) \ + == RTEMS_SUCCESSFUL ) + +#define PIPE_UNLOCK(_pipe) rtems_semaphore_release(_pipe->Semaphore) + +#define PIPE_READWAIT(_pipe) \ + ( rtems_barrier_wait(_pipe->readBarrier, RTEMS_NO_TIMEOUT) \ + == RTEMS_SUCCESSFUL) + +#define PIPE_WRITEWAIT(_pipe) \ + ( rtems_barrier_wait(_pipe->writeBarrier, RTEMS_NO_TIMEOUT) \ + == RTEMS_SUCCESSFUL) + +#define PIPE_WAKEUPREADERS(_pipe) \ + do {uint32_t n; rtems_barrier_release(_pipe->readBarrier, &n); } while(0) + +#define PIPE_WAKEUPWRITERS(_pipe) \ + do {uint32_t n; rtems_barrier_release(_pipe->writeBarrier, &n); } while(0) + + +#ifdef RTEMS_POSIX_API + +#include +#include + +/* Set barriers to be interruptible by signals. */ +static void pipe_interruptible(pipe_control_t *pipe) +{ + Objects_Locations location; + + _Barrier_Get(pipe->readBarrier, &location)->Barrier.Wait_queue.state + |= STATES_INTERRUPTIBLE_BY_SIGNAL; + _Thread_Enable_dispatch(); + _Barrier_Get(pipe->writeBarrier, &location)->Barrier.Wait_queue.state + |= STATES_INTERRUPTIBLE_BY_SIGNAL; + _Thread_Enable_dispatch(); +} +#endif + +/* + * Alloc pipe control structure, buffer, and resources. + * Called with rtems_pipe_semaphore held. + */ +static int pipe_alloc( + pipe_control_t **pipep +) +{ + static char c = 'a'; + pipe_control_t *pipe; + int err = -ENOMEM; + + pipe = malloc(sizeof(pipe_control_t)); + if (pipe == NULL) + return err; + memset(pipe, 0, sizeof(pipe_control_t)); + + pipe->Size = PIPE_BUF; + pipe->Buffer = malloc(pipe->Size); + if (! pipe->Buffer) + goto err_buf; + + err = -EINTR; + if (rtems_barrier_create( + rtems_build_name ('P', 'I', 'r', c), + RTEMS_BARRIER_MANUAL_RELEASE, 0, + &pipe->readBarrier) != RTEMS_SUCCESSFUL) + goto err_rbar; + if (rtems_barrier_create( + rtems_build_name ('P', 'I', 'w', c), + RTEMS_BARRIER_MANUAL_RELEASE, 0, + &pipe->writeBarrier) != RTEMS_SUCCESSFUL) + goto err_wbar; + if (rtems_semaphore_create( + rtems_build_name ('P', 'I', 's', c), 1, + RTEMS_BINARY_SEMAPHORE | RTEMS_FIFO, + RTEMS_NO_PRIORITY, &pipe->Semaphore) != RTEMS_SUCCESSFUL) + goto err_sem; + +#ifdef RTEMS_POSIX_API + pipe_interruptible(pipe); +#endif + + *pipep = pipe; + if (c ++ == 'z') + c = 'a'; + return 0; + +err_sem: + rtems_barrier_delete(pipe->writeBarrier); +err_wbar: + rtems_barrier_delete(pipe->readBarrier); +err_rbar: + free(pipe->Buffer); +err_buf: + free(pipe); + return err; +} + +/* Called with rtems_pipe_semaphore held. */ +static inline void pipe_free( + pipe_control_t *pipe +) +{ + rtems_barrier_delete(pipe->readBarrier); + rtems_barrier_delete(pipe->writeBarrier); + rtems_semaphore_delete(pipe->Semaphore); + free(pipe->Buffer); + free(pipe); +} + +/* + * If called with *pipep = NULL, pipe_new will call pipe_alloc to allocate a + * pipe control structure and set *pipep to its address. + * pipe is locked, when pipe_new returns with no error. + */ +static int pipe_new( + pipe_control_t **pipep +) +{ + pipe_control_t *pipe; + int err = 0; + + if (rtems_semaphore_obtain(rtems_pipe_semaphore, + RTEMS_WAIT, RTEMS_NO_TIMEOUT) != RTEMS_SUCCESSFUL) + return -EINTR; + + pipe = *pipep; + if (pipe == NULL) { + err = pipe_alloc(&pipe); + if (err) + goto out; + } + + if (! PIPE_LOCK(pipe)) + err = -EINTR; + + if (*pipep == NULL) { + if (err) + pipe_free(pipe); + else + *pipep = pipe; + } + +out: + rtems_semaphore_release(rtems_pipe_semaphore); + return err; +} + +/* + * Interface to file system close. + * + * *pipep points to pipe control structure. When the last user releases pipe, + * it will be set to NULL. + */ +int pipe_release( + pipe_control_t **pipep, + rtems_libio_t *iop +) +{ + pipe_control_t *pipe = *pipep; + uint32_t mode; + + rtems_status_code sc; + sc = rtems_semaphore_obtain(pipe->Semaphore, + RTEMS_WAIT, RTEMS_NO_TIMEOUT); + /* WARN pipe not released! */ + if(sc != RTEMS_SUCCESSFUL) + rtems_fatal_error_occurred(sc); + + mode = LIBIO_ACCMODE(iop); + if (mode & LIBIO_FLAGS_READ) + pipe->Readers --; + if (mode & LIBIO_FLAGS_WRITE) + pipe->Writers --; + + sc = rtems_semaphore_obtain(rtems_pipe_semaphore, + RTEMS_WAIT, RTEMS_NO_TIMEOUT); + /* WARN pipe not freed and pipep not set to NULL! */ + if(sc != RTEMS_SUCCESSFUL) + rtems_fatal_error_occurred(sc); + + PIPE_UNLOCK(pipe); + + if (pipe->Readers == 0 && pipe->Writers == 0) { +#if 0 + /* To delete an anonymous pipe file when all users closed it */ + if (pipe->Anonymous) + delfile = TRUE; +#endif + pipe_free(pipe); + *pipep = NULL; + } + else if (pipe->Readers == 0 && mode != LIBIO_FLAGS_WRITE) + /* Notify waiting Writers that all their partners left */ + PIPE_WAKEUPWRITERS(pipe); + else if (pipe->Writers == 0 && mode != LIBIO_FLAGS_READ) + PIPE_WAKEUPREADERS(pipe); + + rtems_semaphore_release(rtems_pipe_semaphore); + +#if 0 + if (! delfile) + return 0; + if (iop->pathinfo.ops->unlink_h == NULL) + return 0; + + /* This is safe for IMFS, but how about other FSes? */ + iop->flags &= ~LIBIO_FLAGS_OPEN; + if(iop->pathinfo.ops->unlink_h(&iop->pathinfo)) + return -errno; +#endif + + return 0; +} + +/* + * Interface to file system open. + * + * *pipep points to pipe control structure. If called with *pipep = NULL, + * fifo_open will try allocating and initializing a control structure. If the + * call succeeds, *pipep will be set to address of new control structure. + */ +int fifo_open( + pipe_control_t **pipep, + rtems_libio_t *iop +) +{ + pipe_control_t *pipe; + uint prevCounter; + int err; + + err = pipe_new(pipep); + if (err) + return err; + pipe = *pipep; + + switch (LIBIO_ACCMODE(iop)) { + case LIBIO_FLAGS_READ: + pipe->readerCounter ++; + if (pipe->Readers ++ == 0) + PIPE_WAKEUPWRITERS(pipe); + + if (pipe->Writers == 0) { + /* Not an error */ + if (LIBIO_NODELAY(iop)) + break; + + prevCounter = pipe->writerCounter; + err = -EINTR; + /* Wait until a writer opens the pipe */ + do { + PIPE_UNLOCK(pipe); + if (! PIPE_READWAIT(pipe)) + goto out_error; + if (! PIPE_LOCK(pipe)) + goto out_error; + } while (prevCounter == pipe->writerCounter); + } + break; + + case LIBIO_FLAGS_WRITE: + if (pipe->Readers == 0 && LIBIO_NODELAY(iop)) { + err = -ENXIO; + goto out_error; + } + + pipe->writerCounter ++; + if (pipe->Writers ++ == 0) + PIPE_WAKEUPREADERS(pipe); + + if (pipe->Readers == 0) { + prevCounter = pipe->readerCounter; + err = -EINTR; + do { + PIPE_UNLOCK(pipe); + if (! PIPE_WRITEWAIT(pipe)) + goto out_error; + if (! PIPE_LOCK(pipe)) + goto out_error; + } while (prevCounter == pipe->readerCounter); + } + break; + + case LIBIO_FLAGS_READ_WRITE: + pipe->readerCounter ++; + if (pipe->Readers ++ == 0) + PIPE_WAKEUPWRITERS(pipe); + pipe->writerCounter ++; + if (pipe->Writers ++ == 0) + PIPE_WAKEUPREADERS(pipe); + break; + } + + PIPE_UNLOCK(pipe); + return 0; + +out_error: + pipe_release(pipep, iop); + return err; +} + +/* + * Interface to file system read. + */ +ssize_t pipe_read( + pipe_control_t *pipe, + void *buffer, + size_t count, + rtems_libio_t *iop +) +{ + int chunk, chunk1, read = 0, ret = 0; + + if (! PIPE_LOCK(pipe)) + return -EINTR; + + while (read < count) { + while (PIPE_EMPTY(pipe)) { + /* Not an error */ + if (pipe->Writers == 0) + goto out_locked; + + if (LIBIO_NODELAY(iop)) { + ret = -EAGAIN; + goto out_locked; + } + + /* Wait until pipe is no more empty or no writer exists */ + pipe->waitingReaders ++; + PIPE_UNLOCK(pipe); + if (! PIPE_READWAIT(pipe)) + ret = -EINTR; + if (! PIPE_LOCK(pipe)) { + /* WARN waitingReaders not restored! */ + ret = -EINTR; + goto out_nolock; + } + pipe->waitingReaders --; + if (ret != 0) + goto out_locked; + } + + /* Read chunk bytes */ + chunk = MIN(count - read, pipe->Length); + chunk1 = pipe->Size - pipe->Start; + if (chunk > chunk1) { + memcpy(buffer + read, pipe->Buffer + pipe->Start, chunk1); + memcpy(buffer + read + chunk1, pipe->Buffer, chunk - chunk1); + } + else + memcpy(buffer + read, pipe->Buffer + pipe->Start, chunk); + + pipe->Start += chunk; + pipe->Start %= pipe->Size; + pipe->Length -= chunk; + /* For buffering optimization */ + if (PIPE_EMPTY(pipe)) + pipe->Start = 0; + + if (pipe->waitingWriters > 0) + PIPE_WAKEUPWRITERS(pipe); + read += chunk; + } + +out_locked: + PIPE_UNLOCK(pipe); + +out_nolock: + if (read > 0) + return read; + return ret; +} + +/* + * Interface to file system write. + */ +ssize_t pipe_write( + pipe_control_t *pipe, + const void *buffer, + size_t count, + rtems_libio_t *iop +) +{ + int chunk, chunk1, written = 0, ret = 0; + + /* Write nothing */ + if (count == 0) + return 0; + + if (! PIPE_LOCK(pipe)) + return -EINTR; + + if (pipe->Readers == 0) { + ret = -EPIPE; + goto out_locked; + } + + /* Write of PIPE_BUF bytes or less shall not be interleaved */ + chunk = count <= pipe->Size ? count : 1; + + while (written < count) { + while (PIPE_SPACE(pipe) < chunk) { + if (LIBIO_NODELAY(iop)) { + ret = -EAGAIN; + goto out_locked; + } + + /* Wait until there is chunk bytes space or no reader exists */ + pipe->waitingWriters ++; + PIPE_UNLOCK(pipe); + if (! PIPE_WRITEWAIT(pipe)) + ret = -EINTR; + if (! PIPE_LOCK(pipe)) { + /* WARN waitingWriters not restored! */ + ret = -EINTR; + goto out_nolock; + } + pipe->waitingWriters --; + if (ret != 0) + goto out_locked; + + if (pipe->Readers == 0) { + ret = -EPIPE; + goto out_locked; + } + } + + chunk = MIN(count - written, PIPE_SPACE(pipe)); + chunk1 = pipe->Size - PIPE_WSTART(pipe); + if (chunk > chunk1) { + memcpy(pipe->Buffer + PIPE_WSTART(pipe), buffer + written, chunk1); + memcpy(pipe->Buffer, buffer + written + chunk1, chunk - chunk1); + } + else + memcpy(pipe->Buffer + PIPE_WSTART(pipe), buffer + written, chunk); + + pipe->Length += chunk; + if (pipe->waitingReaders > 0) + PIPE_WAKEUPREADERS(pipe); + written += chunk; + /* Write of more than PIPE_BUF bytes can be interleaved */ + chunk = 1; + } + +out_locked: + PIPE_UNLOCK(pipe); + +out_nolock: +#ifdef RTEMS_POSIX_API + /* Signal SIGPIPE */ + if (ret == -EPIPE) + kill(getpid(), SIGPIPE); +#endif + + if (written > 0) + return written; + return ret; +} + +/* + * Interface to file system ioctl. + */ +int pipe_ioctl( + pipe_control_t *pipe, + uint32_t cmd, + void *buffer, + rtems_libio_t *iop +) +{ + if (cmd == FIONREAD) { + if (buffer == NULL) + return -EFAULT; + + if (! PIPE_LOCK(pipe)) + return -EINTR; + + /* Return length of pipe */ + *(uint *)buffer = pipe->Length; + PIPE_UNLOCK(pipe); + return 0; + } + + return -EINVAL; +} + +/* + * Interface to file system lseek. + */ +int pipe_lseek( + pipe_control_t *pipe, + off_t offset, + int whence, + rtems_libio_t *iop +) +{ + /* Seek on pipe is not supported */ + return -ESPIPE; +} + +/* + * Initialization of FIFO/pipe module. + */ +void rtems_pipe_initialize (void) +{ + if (rtems_pipe_semaphore) + return; + + rtems_status_code sc; + sc = rtems_semaphore_create( + rtems_build_name ('P', 'I', 'P', 'E'), 1, + RTEMS_BINARY_SEMAPHORE | RTEMS_INHERIT_PRIORITY | RTEMS_PRIORITY, + RTEMS_NO_PRIORITY, &rtems_pipe_semaphore); + if (sc != RTEMS_SUCCESSFUL) + rtems_fatal_error_occurred (sc); + + rtems_interval now; + rtems_clock_get(RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &now); + rtems_pipe_no = now; +} diff --git a/cpukit/libfs/src/pipe/pipe.c b/cpukit/libfs/src/pipe/pipe.c new file mode 100644 index 0000000000..339aa42f4e --- /dev/null +++ b/cpukit/libfs/src/pipe/pipe.c @@ -0,0 +1,83 @@ +/* + * pipe.c: anonymous pipe + * + * Author: Wei Shen + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#include +#include +#include +#include + +/* Incremental number added to names of anonymous pipe files */ +uint16_t rtems_pipe_no = 0; + +/* + * Called by pipe() to create an anonymous pipe. + */ +int pipe_create( + int filsdes[2] +) +{ + rtems_filesystem_location_info_t loc; + rtems_libio_t *iop; + int err = 0; + + /* Create /tmp if not exists */ + if (rtems_filesystem_evaluate_path("/tmp", RTEMS_LIBIO_PERMS_RWX, &loc, TRUE) + != 0) { + if (errno != ENOENT) + return -1; + if (mkdir("/tmp", S_IRWXU|S_IRWXG|S_IRWXO|S_ISVTX) != 0) + return -1; + } + else + rtems_filesystem_freenode(&loc); + + /* /tmp/.fifoXXXX */ + char fifopath[15]; + memcpy(fifopath, "/tmp/.fifo", 10); + sprintf(fifopath + 10, "%04x", rtems_pipe_no ++); + + /* Try creating FIFO file until find an available file name */ + while (mkfifo(fifopath, S_IRUSR|S_IWUSR) != 0) { + if (errno != EEXIST) + return -1; + /* Just try once... */ + return -1; + sprintf(fifopath + 10, "%04x", rtems_pipe_no ++); + } + + /* Non-blocking open to avoid waiting for writers */ + filsdes[0] = open(fifopath, O_RDONLY | O_NONBLOCK); + if (filsdes[0] < 0) { + err = errno; + goto out; + } + + /* Reset open file to blocking mode */ + iop = rtems_libio_iop(filsdes[0]); + iop->flags &= ~LIBIO_FLAGS_NO_DELAY; + + filsdes[1] = open(fifopath, O_WRONLY); + + if (filsdes[1] < 0) { + err = errno; + close(filsdes[0]); + } + +out: + /* Delete file at errors, or else if pipe is successfully created + the file node will be deleted after it is closed by all. */ + unlink(fifopath); + + if (! err) + return 0; + rtems_set_errno_and_return_minus_one(err); +} diff --git a/cpukit/libfs/src/pipe/pipe.h b/cpukit/libfs/src/pipe/pipe.h new file mode 100644 index 0000000000..54f7525524 --- /dev/null +++ b/cpukit/libfs/src/pipe/pipe.h @@ -0,0 +1,113 @@ +/* + * pipe.h: header of POSIX FIFO/pipe + * + * Author: Wei Shen + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#ifndef _RTEMS_PIPE_H +#define _RTEMS_PIPE_H + +#include + +/* Control block to manage each pipe */ +typedef struct pipe_control { + char *Buffer; + uint Size; + uint Start; + uint Length; + uint Readers; + uint Writers; + uint waitingReaders; + uint waitingWriters; + uint readerCounter; /* incremental counters */ + uint writerCounter; /* for differentiation of successive opens */ + rtems_id Semaphore; + rtems_id readBarrier; /* wait queues */ + rtems_id writeBarrier; +#if 0 + boolean Anonymous; /* anonymous pipe or FIFO */ +#endif +} pipe_control_t; + +/* + * Called by pipe() to create an anonymous pipe. + */ +int pipe_create( + int filsdes[2] +); + +/* + * Interface to file system close. + * + * *pipep points to pipe control structure. When the last user releases pipe, + * it will be set to NULL. + */ +int pipe_release( + pipe_control_t **pipep, + rtems_libio_t *iop +); + +/* + * Interface to file system open. + * + * *pipep points to pipe control structure. If called with *pipep = NULL, + * fifo_open will try allocating and initializing a control structure. If the + * call succeeds, *pipep will be set to address of new control structure. + */ +int fifo_open( + pipe_control_t **pipep, + rtems_libio_t *iop +); + +/* + * Interface to file system read. + */ +ssize_t pipe_read( + pipe_control_t *pipe, + void *buffer, + size_t count, + rtems_libio_t *iop +); + +/* + * Interface to file system write. + */ +ssize_t pipe_write( + pipe_control_t *pipe, + const void *buffer, + size_t count, + rtems_libio_t *iop +); + +/* + * Interface to file system ioctl. + */ +int pipe_ioctl( + pipe_control_t *pipe, + uint32_t cmd, + void *buffer, + rtems_libio_t *iop +); + +/* + * Interface to file system lseek. + */ +int pipe_lseek( + pipe_control_t *pipe, + off_t offset, + int whence, + rtems_libio_t *iop +); + +/* + * Initialization of FIFO/pipe module. + */ +void rtems_pipe_initialize (void); + +#endif /* #define _RTEMS_PIPE_H */ -- cgit v1.2.3