summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2012-04-12 17:15:53 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2012-04-12 17:17:56 +0200
commit1f16a9f801016b6a636e92bef4813f238e4b4f98 (patch)
tree303000973a5ee97486c4fce79f8dabd8986f5eee
parentMerge branch 'upstream' (diff)
downloadrtems-1f16a9f801016b6a636e92bef4813f238e4b4f98.tar.bz2
Filesystem: Add select() support for pipes
-rw-r--r--cpukit/libfs/src/pipe/fifo.c96
-rw-r--r--cpukit/libfs/src/pipe/pipe.h2
2 files changed, 86 insertions, 12 deletions
diff --git a/cpukit/libfs/src/pipe/fifo.c b/cpukit/libfs/src/pipe/fifo.c
index d80a51f8cc..31ccfc8193 100644
--- a/cpukit/libfs/src/pipe/fifo.c
+++ b/cpukit/libfs/src/pipe/fifo.c
@@ -68,6 +68,21 @@ static rtems_id pipe_semaphore = RTEMS_ID_NONE;
#include <rtems/rtems/barrier.h>
#include <rtems/score/thread.h>
+static void pipe_select_wakeup(rtems_id *id_ptr)
+{
+ rtems_id id = *id_ptr;
+
+ *id_ptr = 0;
+
+ if (id != 0) {
+ rtems_status_code sc = rtems_event_send(id, RTEMS_IOCTL_SELECT_EVENT);
+
+ if (sc != RTEMS_SUCCESSFUL) {
+ rtems_fatal_error_occurred(sc);
+ }
+ }
+}
+
/* Set barriers to be interruptible by signals. */
static void pipe_interruptible(pipe_control_t *pipe)
{
@@ -94,10 +109,9 @@ static int pipe_alloc(
pipe_control_t *pipe;
int err = -ENOMEM;
- pipe = malloc(sizeof(pipe_control_t));
+ pipe = calloc(1, 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);
@@ -447,6 +461,7 @@ ssize_t pipe_read(
if (PIPE_EMPTY(pipe))
pipe->Start = 0;
+ pipe_select_wakeup(&pipe->select_write_task_id);
if (pipe->waitingWriters > 0)
PIPE_WAKEUPWRITERS(pipe);
read += chunk;
@@ -525,6 +540,7 @@ ssize_t pipe_write(
memcpy(pipe->Buffer + PIPE_WSTART(pipe), buffer + written, chunk);
pipe->Length += chunk;
+ pipe_select_wakeup(&pipe->select_read_task_id);
if (pipe->waitingReaders > 0)
PIPE_WAKEUPREADERS(pipe);
written += chunk;
@@ -547,6 +563,53 @@ out_nolock:
return ret;
}
+static int pipe_register_select_wakeup(
+ rtems_id *id_ptr,
+ const rtems_ioctl_select_request *request
+)
+{
+ int rv = 0;
+ rtems_id current_id = *id_ptr;
+ rtems_id request_id = request->request_task_id;
+
+ if (current_id == 0 || current_id == request_id) {
+ *id_ptr = request_id;
+ } else {
+ rv = -EINVAL;
+ }
+
+ return rv;
+}
+
+static int pipe_select(
+ pipe_control_t *pipe,
+ const rtems_ioctl_select_request *request
+)
+{
+ int rv = 0;
+
+ switch (request->kind) {
+ case RTEMS_IOCTL_SELECT_READ:
+ if (!PIPE_EMPTY(pipe)) {
+ rv = 1;
+ } else {
+ rv = pipe_register_select_wakeup(&pipe->select_read_task_id, request);
+ }
+ break;
+ case RTEMS_IOCTL_SELECT_WRITE:
+ if (PIPE_SPACE(pipe) > 0) {
+ rv = 1;
+ } else {
+ rv = pipe_register_select_wakeup(&pipe->select_write_task_id, request);
+ }
+ break;
+ default:
+ break;
+ }
+
+ return rv;
+}
+
/*
* Interface to file system ioctl.
*/
@@ -557,20 +620,29 @@ int pipe_ioctl(
rtems_libio_t *iop
)
{
- if (cmd == FIONREAD) {
- if (buffer == NULL)
- return -EFAULT;
+ int rv = 0;
- if (! PIPE_LOCK(pipe))
- return -EINTR;
+ if (buffer != NULL) {
+ if (PIPE_LOCK(pipe)) {
+ switch (cmd) {
+ case RTEMS_IOCTL_SELECT:
+ rv = pipe_select(pipe, buffer);
+ break;
+ case FIONREAD:
+ /* Return length of pipe */
+ *(unsigned int *) buffer = pipe->Length;
+ break;
+ }
- /* Return length of pipe */
- *(unsigned int *)buffer = pipe->Length;
- PIPE_UNLOCK(pipe);
- return 0;
+ PIPE_UNLOCK(pipe);
+ } else {
+ rv = -EINTR;
+ }
+ } else {
+ rv = -EFAULT;
}
- return -EINVAL;
+ return rv;
}
/*
diff --git a/cpukit/libfs/src/pipe/pipe.h b/cpukit/libfs/src/pipe/pipe.h
index 52d0a85143..97358eb61e 100644
--- a/cpukit/libfs/src/pipe/pipe.h
+++ b/cpukit/libfs/src/pipe/pipe.h
@@ -39,6 +39,8 @@ typedef struct pipe_control {
rtems_id Semaphore;
rtems_id readBarrier; /* wait queues */
rtems_id writeBarrier;
+ rtems_id select_read_task_id;
+ rtems_id select_write_task_id;
#if 0
boolean Anonymous; /* anonymous pipe or FIFO */
#endif