aboutsummaryrefslogtreecommitdiff
path: root/libpipe/pipe.h
diff options
context:
space:
mode:
authorMiles Bader <miles@gnu.org>1995-07-26 20:09:37 +0000
committerMiles Bader <miles@gnu.org>1995-07-26 20:09:37 +0000
commit760c406afd447f94677ee207e20f52ddcb8fbf18 (patch)
tree08726a433179d5b3fa33fb7c30faa48bee361f4f /libpipe/pipe.h
parent8d853d3864c42e5ff9e257976cb38882b0a3c44c (diff)
downloadhurd-760c406afd447f94677ee207e20f52ddcb8fbf18.tar.gz
hurd-760c406afd447f94677ee207e20f52ddcb8fbf18.tar.bz2
hurd-760c406afd447f94677ee207e20f52ddcb8fbf18.zip
Initial revision
Diffstat (limited to 'libpipe/pipe.h')
-rw-r--r--libpipe/pipe.h254
1 files changed, 254 insertions, 0 deletions
diff --git a/libpipe/pipe.h b/libpipe/pipe.h
new file mode 100644
index 00000000..022db1f3
--- /dev/null
+++ b/libpipe/pipe.h
@@ -0,0 +1,254 @@
+/* Generic one-way pipes
+
+ Copyright (C) 1995 Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.ai.mit.edu>
+
+ 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, 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef __PIPE_H__
+#define __PIPE_H__
+
+#include <cthreads.h> /* For conditions & mutexes */
+
+#include "pq.h"
+
+/* A description of a class of pipes and how to operate on them. */
+struct pipe_class
+{
+ /* What sort of socket this corresponds too. */
+ int sock_type;
+
+ /* Flags, from PIPE_CLASS_*, below. */
+ unsigned flags;
+
+ /* Operations: */
+ /* Read from PACKET into DATA &c, and set *DEQUEUE to true if PACKET should
+ be subsequently discarded. */
+ error_t (*read)(struct packet *packet, int *dequeue, unsigned *flags,
+ char **data, size_t *data_len, size_t amount);
+ /* Write DATA &c into the packet queue PQ. */
+ error_t (*write)(struct pq *pq, void *source,
+ char *data, size_t data_len, size_t *amount);
+};
+
+/* pipe_class flags */
+#define PIPE_CLASS_CONNECTIONLESS 0x1 /* A non-stream protocol. */
+
+/* Some pre-defined pipe_classes. */
+struct pipe_class *stream_pipe_class;
+struct pipe_class *dgram_pipe_class;
+struct pipe_class *seqpacket_pipe_class;
+
+/* A unidirectional data pipe; it transfers data from READER to WRITER. */
+struct pipe
+{
+ /* What kind of pipe we are. */
+ struct pipe_class *class;
+
+ /* We use this to keep track of active threads using this pipe, so that
+ while a thread is waiting to read from a pipe and that pipe gets
+ deallocated (say by socket_shutdown), it doesn't actually go away until
+ the reader realizes what happened. It is normally frobbed using
+ pipe_aquire & pipe_release, which do locking as well.. */
+ unsigned refs;
+
+ /* Various flags, from PIPE_* below. */
+ unsigned flags;
+
+ /* Various timestamps for this pipe. */
+ time_value_t read_time;
+ time_value_t write_time;
+
+ struct condition pending_reads;
+ struct condition pending_selects;
+
+ struct mutex lock;
+
+ /* When a pipe receives an interrupt, we want to wake up all pending read
+ threads, and have them realize they've been interrupted; reads that
+ happen after the interrupt shouldn't return EINTR. When a thread waits
+ on this pipe's PENDING_READS condition, it remembers this sequence
+ number; any interrupt bumps this number and broadcasts on the condition.
+ A reader thread will try to read from the pipe only if the sequence
+ number is the same as when it went to sleep. */
+ unsigned long interrupt_seq_num;
+
+ /* A queue of incoming packets, of type either PACKET_TYPE_DATA or
+ PACKET_TYPE_CONTROL. Each data packet represents one datagram for
+ protocols that maintain record boundaries. Control packets always
+ represent the control information to be returned from one read
+ operation, and will be returned in conjuction with the following data
+ packet (if any). Reads interested only in data just skip control
+ packets until they find a data packet. */
+ struct pq *queue;
+};
+
+/* Pipe flags. */
+#define PIPE_BROKEN 0x1 /* This pipe isn't connected. */
+
+/* Returns the number of characters quickly readable from PIPE. If DATA_ONLY
+ is true, then `control' packets are ignored. */
+extern inline size_t
+pipe_readable (struct pipe *pipe, int data_only)
+{
+ size_t readable = 0;
+ struct pq *pq = pipe->queue;
+ struct packet *packet = pq_head (pq, PACKET_TYPE_ANY, NULL);
+ while (packet)
+ {
+ if (packet->type == PACKET_TYPE_DATA)
+ readable += packet_readable (packet);
+ packet = packet->next;
+ }
+ return readable;
+}
+
+/* Returns true if there's any data available in PIPE. If DATA_ONLY is true,
+ then `control' packets are ignored. Note that this is different than
+ (pipe_readable (PIPE) > 0) in the case where a control packet containing
+ only ports is present. */
+extern inline int
+pipe_is_readable (struct pipe *pipe, int data_only)
+{
+ struct pq *pq = pipe->queue;
+ struct packet *packet = pq_head (pq, PACKET_TYPE_ANY, NULL);
+ if (data_only)
+ while (packet && packet->type == PACKET_TYPE_CONTROL)
+ packet = packet->next;
+ return (packet != NULL);
+}
+
+/* Waits for PIPE to be readable, or an error to occurr. If NOBLOCK is true,
+ this operation will return EWOULDBLOCK instead of blocking when no data is
+ immediately available. If DATA_ONLY is true, then `control' packets are
+ ignored. */
+extern inline error_t
+pipe_wait (struct pipe *pipe, int noblock, int data_only)
+{
+ while (! pipe_is_readable (pipe, data_only) && ! (pipe->flags & PIPE_BROKEN))
+ {
+ unsigned seq_num = pipe->interrupt_seq_num;
+ if (noblock)
+ return EWOULDBLOCK;
+ condition_wait (&pipe->pending_reads, &pipe->lock);
+ if (seq_num != pipe->interrupt_seq_num)
+ return EINTR;
+ }
+ return 0;
+}
+
+/* Wake up all threads waiting on PIPE, which should be locked. */
+void pipe_kick (struct pipe *pipe);
+
+/* Creates a new pipe of class CLASS and returns it in RESULT. */
+error_t pipe_create (struct pipe_class *class, struct pipe **pipe);
+
+/* Free PIPE and any resources it holds. */
+void pipe_free (struct pipe *pipe);
+
+/* Discard a reference to PIPE, which should be unlocked, being sure to make
+ users aware of this. */
+void pipe_break (struct pipe *pipe);
+
+/* Lock PIPE and increment its ref count. */
+extern inline void
+pipe_aquire (struct pipe *pipe)
+{
+ mutex_lock (&pipe->lock);
+ pipe->refs++;
+}
+
+/* Decrement PIPE's (which should be locked) ref count and unlock it. If the
+ ref count goes to zero, PIPE will be destroyed. */
+extern inline void
+pipe_release (struct pipe *pipe)
+{
+ if (--pipe->refs == 0)
+ pipe_free (pipe);
+ else
+ mutex_unlock (&pipe->lock);
+}
+
+/* Empty out PIPE of any data. PIPE should be locked. */
+extern inline void
+pipe_drain (struct pipe *pipe)
+{
+ pq_drain (pipe->queue);
+}
+
+/* Writes up to LEN bytes of DATA, to PIPE, which should be locked, and
+ returns the amount written in AMOUNT. If present, the information in
+ CONTROL & PORTS is written in a preceding control packet. If an error is
+ returned, nothing is done. If non-NULL, SOURCE is recorded as the source
+ of the data, to be provided to any readers of it; if no reader ever reads
+ it, it's deallocated by calling pipe_dealloc_addr. */
+error_t pipe_send (struct pipe *pipe, void *source,
+ char *data, size_t data_len,
+ char *control, size_t control_len,
+ mach_port_t *ports, size_t num_ports,
+ size_t *amount);
+
+/* Writes up to LEN bytes of DATA, to PIPE, which should be locked, and
+ returns the amount written in AMOUNT. If an error is returned, nothing is
+ done. If non-NULL, SOURCE is recorded as the source of the data, to be
+ provided to any readers of it; if no reader ever reads it, it's
+ deallocated by calling pipe_dealloc_addr. */
+#define pipe_write(pipe, source, data, data_len, amount) \
+ pipe_send (pipe, source, data, data_len, 0, 0, 0, 0, amount)
+
+/* Reads up to AMOUNT bytes from PIPE, which should be locked, into DATA, and
+ returns the amount read in DATA_LEN. If NOBLOCK is true, EWOULDBLOCK is
+ returned instead of block when no data is immediately available. If an
+ error is returned, nothing is done. If source isn't NULL, the
+ corresponding source provided by the sender is returned in it; this may be
+ NULL if it wasn't specified by the sender (which is usually the case with
+ connection-oriented protcols).
+
+ If there is control data waiting (before any data), then the behavior
+ depends on whether this is an `ordinary read' (when CONTROL and PORTS are
+ both NULL), in which case any control data is skipped, or a `msg read', in
+ which case the contents of the first control packet is returned (in
+ CONTROL and PORTS), as well as the first data packet following that (if
+ the control packet is followed by another control packet or no packet in
+ this case, a zero length data buffer is returned; the user should be
+ careful to distinguish this case from EOF (when no control or ports data
+ is returned either). */
+error_t pipe_recv (struct pipe *pipe, int noblock, unsigned *flags,
+ void **source,
+ char **data, size_t *data_len, size_t amount,
+ char **control, size_t *control_len,
+ mach_port_t **ports, size_t *num_ports);
+
+
+/* Reads up to AMOUNT bytes from PIPE, which should be locked, into DATA, and
+ returns the amount read in DATA_LEN. If NOBLOCK is true, EWOULDBLOCK is
+ returned instead of block when no data is immediately available. If an
+ error is returned, nothing is done. If source isn't NULL, the
+ corresponding source provided by the sender is returned in it; this may be
+ NULL if it wasn't specified by the sender (which is usually the case with
+ connection-oriented protcols). */
+#define pipe_read(pipe, noblock, source, data, data_len, amount) \
+ pipe_recv (pipe, noblock, 0, source, data, data_len, amount, 0,0,0,0)
+
+/* ---------------------------------------------------------------- */
+/* User-provided functions. */
+
+/* This routine may be provided by the user, in which case, it should be a
+ function taking a non-NULL source address and deallocating it. It
+ defaults to calling ports_port_deref. */
+void pipe_dealloc_addr (void *addr);
+
+#endif /* __PIPE_H__ */