/*
 * 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;
}
Esempio n. 2
0
/*
 * Interface to file system close.
 *
 * *pipep points to pipe control structure. When the last user releases pipe,
 * it will be set to NULL.
 */
void pipe_release(
  pipe_control_t **pipep,
  rtems_libio_t *iop
)
{
  pipe_control_t *pipe = *pipep;
  uint32_t mode;

  #if defined(RTEMS_DEBUG)
    /* WARN pipe not freed and pipep not set to NULL! */
    if (pipe_lock())
      rtems_fatal_error_occurred(0xdeadbeef);

    /* WARN pipe not released! */
    if (!PIPE_LOCK(pipe))
      rtems_fatal_error_occurred(0xdeadbeef);
  #endif

  mode = LIBIO_ACCMODE(iop);
  if (mode & LIBIO_FLAGS_READ)
     pipe->Readers --;
  if (mode & LIBIO_FLAGS_WRITE)
     pipe->Writers --;

  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);

  pipe_unlock();

#if 0
  if (! delfile)
    return;
  if (iop->pathinfo.ops->unlink_h == NULL)
    return;

  /* This is safe for IMFS, but how about other FSes? */
  iop->flags &= ~LIBIO_FLAGS_OPEN;
  if(iop->pathinfo.ops->unlink_h(&iop->pathinfo))
    return;
#endif

}
/*
 * 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 */
    *(unsigned int *)buffer = pipe->Length;
    PIPE_UNLOCK(pipe);
    return 0;
  }

  return -EINVAL;
}
/*
 * 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 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 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;
  unsigned int 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:
      pipe->writerCounter ++;

      if (pipe->Writers ++ == 0)
        PIPE_WAKEUPREADERS(pipe);

      if (pipe->Readers == 0 && LIBIO_NODELAY(iop)) {
	PIPE_UNLOCK(pipe);
        err = -ENXIO;
        goto out_error;
      }

      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;
}
Esempio n. 7
0
int
pipe_stat(struct pipe *cpipe, void *ub, int isstat64)
{
#if CONFIG_MACF
        int error;
#endif
	int	pipe_size = 0;
	int	pipe_count;
	struct stat *sb = (struct stat *)0;	/* warning avoidance ; protected by isstat64 */
	struct stat64 * sb64 = (struct stat64 *)0;  /* warning avoidance ; protected by isstat64 */

	if (cpipe == NULL)
	        return (EBADF);
	PIPE_LOCK(cpipe);

#if CONFIG_MACF
	error = mac_pipe_check_stat(kauth_cred_get(), cpipe);
	if (error) {
		PIPE_UNLOCK(cpipe);
	        return (error);
	}
#endif
	if (cpipe->pipe_buffer.buffer == 0) {
	        /* must be stat'ing the write fd */
	        if (cpipe->pipe_peer) {
		        /* the peer still exists, use it's info */
		        pipe_size  = MAX_PIPESIZE(cpipe->pipe_peer);
			pipe_count = cpipe->pipe_peer->pipe_buffer.cnt;
		} else {
			pipe_count = 0;
		}
	} else {
	        pipe_size  = MAX_PIPESIZE(cpipe);
		pipe_count = cpipe->pipe_buffer.cnt;
	}
	/*
	 * since peer's buffer is setup ouside of lock
	 * we might catch it in transient state
	 */
	if (pipe_size == 0)
		pipe_size  = MAX(PIPE_SIZE, pipesize_blocks[0]);

	if (isstat64 != 0) {
		sb64 = (struct stat64 *)ub;	

		bzero(sb64, sizeof(*sb64));
		sb64->st_mode = S_IFIFO | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
		sb64->st_blksize = pipe_size;
		sb64->st_size = pipe_count;
		sb64->st_blocks = (sb64->st_size + sb64->st_blksize - 1) / sb64->st_blksize;
	
		sb64->st_uid = kauth_getuid();
		sb64->st_gid = kauth_getgid();
	
		sb64->st_atimespec.tv_sec  = cpipe->st_atimespec.tv_sec;
		sb64->st_atimespec.tv_nsec = cpipe->st_atimespec.tv_nsec;
	
		sb64->st_mtimespec.tv_sec  = cpipe->st_mtimespec.tv_sec;
		sb64->st_mtimespec.tv_nsec = cpipe->st_mtimespec.tv_nsec;

		sb64->st_ctimespec.tv_sec  = cpipe->st_ctimespec.tv_sec;
		sb64->st_ctimespec.tv_nsec = cpipe->st_ctimespec.tv_nsec;

		/*
	 	* Return a relatively unique inode number based on the current
	 	* address of this pipe's struct pipe.  This number may be recycled
	 	* relatively quickly.
	 	*/
		sb64->st_ino = (ino64_t)VM_KERNEL_ADDRPERM((uintptr_t)cpipe);
	} else {
		sb = (struct stat *)ub;	

		bzero(sb, sizeof(*sb));
		sb->st_mode = S_IFIFO | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
		sb->st_blksize = pipe_size;
		sb->st_size = pipe_count;
		sb->st_blocks = (sb->st_size + sb->st_blksize - 1) / sb->st_blksize;
	
		sb->st_uid = kauth_getuid();
		sb->st_gid = kauth_getgid();
	
		sb->st_atimespec.tv_sec  = cpipe->st_atimespec.tv_sec;
		sb->st_atimespec.tv_nsec = cpipe->st_atimespec.tv_nsec;
	
		sb->st_mtimespec.tv_sec  = cpipe->st_mtimespec.tv_sec;
		sb->st_mtimespec.tv_nsec = cpipe->st_mtimespec.tv_nsec;

		sb->st_ctimespec.tv_sec  = cpipe->st_ctimespec.tv_sec;
		sb->st_ctimespec.tv_nsec = cpipe->st_ctimespec.tv_nsec;

		/*
	 	* Return a relatively unique inode number based on the current
	 	* address of this pipe's struct pipe.  This number may be recycled
	 	* relatively quickly.
	 	*/
		sb->st_ino = (ino_t)VM_KERNEL_ADDRPERM((uintptr_t)cpipe);
	}
	PIPE_UNLOCK(cpipe);

	/*
	 * POSIX: Left as 0: st_dev, st_nlink, st_rdev, st_flags, st_gen,
	 * st_uid, st_gid.
	 *
	 * XXX (st_dev) should be unique, but there is no device driver that
	 * XXX is associated with pipes, since they are implemented via a
	 * XXX struct fileops indirection rather than as FS objects.
	 */
	return (0);
}