Module: xenomai-forge Branch: master Commit: cacb53091dd395a015212154a951b03a268676c9 URL: http://git.xenomai.org/?p=xenomai-forge.git;a=commit;h=cacb53091dd395a015212154a951b03a268676c9
Author: Philippe Gerum <r...@xenomai.org> Date: Sat Nov 12 19:25:14 2011 +0100 alchemy: introduce message pipes (Cobalt only) --- include/alchemy/Makefile.am | 1 + include/alchemy/Makefile.in | 1 + include/alchemy/pipe.h | 78 ++++++++++++ lib/alchemy/Makefile.am | 6 + lib/alchemy/Makefile.in | 51 ++++---- lib/alchemy/pipe.c | 291 +++++++++++++++++++++++++++++++++++++++++++ lib/alchemy/pipe.h | 37 ++++++ 7 files changed, 437 insertions(+), 28 deletions(-) diff --git a/include/alchemy/Makefile.am b/include/alchemy/Makefile.am index 6264677..1216fc4 100644 --- a/include/alchemy/Makefile.am +++ b/include/alchemy/Makefile.am @@ -5,6 +5,7 @@ includesub_HEADERS = \ buffer.h \ cond.h \ mutex.h \ + pipe.h \ queue.h \ sem.h \ task.h \ diff --git a/include/alchemy/Makefile.in b/include/alchemy/Makefile.in index 68d5063..553c483 100644 --- a/include/alchemy/Makefile.in +++ b/include/alchemy/Makefile.in @@ -244,6 +244,7 @@ includesub_HEADERS = \ buffer.h \ cond.h \ mutex.h \ + pipe.h \ queue.h \ sem.h \ task.h \ diff --git a/include/alchemy/pipe.h b/include/alchemy/pipe.h new file mode 100644 index 0000000..2e5ced7 --- /dev/null +++ b/include/alchemy/pipe.h @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2011 Philippe Gerum <r...@xenomai.org>. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _XENOMAI_ALCHEMY_PIPE_H +#define _XENOMAI_ALCHEMY_PIPE_H + +#include <stdint.h> +#include <alchemy/timer.h> + +/* Creation flags. */ +#define P_MINOR_AUTO XNPIPE_MINOR_AUTO + +/* Operation flags. */ +#define P_URGENT 0x1 +#define P_NORMAL 0x0 + +struct RT_PIPE { + uintptr_t handle; +}; + +typedef struct RT_PIPE RT_PIPE; + +#ifdef __cplusplus +extern "C" { +#endif + +int rt_pipe_create(RT_PIPE *pipe, + const char *name, + int minor, + size_t poolsize); + +int rt_pipe_delete(RT_PIPE *pipe); + +ssize_t rt_pipe_read(RT_PIPE *pipe, + void *buf, + size_t size, + RTIME timeout); + +ssize_t rt_pipe_read_until(RT_PIPE *pipe, + void *buf, + size_t size, + RTIME timeout); + +ssize_t rt_pipe_write(RT_PIPE *pipe, + const void *buf, + size_t size, + int mode); + +ssize_t rt_pipe_stream(RT_PIPE *pipe, + const void *buf, + size_t size); + +int rt_pipe_bind(RT_PIPE *pipe, + const char *name, + RTIME timeout); + +int rt_pipe_unbind(RT_PIPE *pipe); + +#ifdef __cplusplus +} +#endif + +#endif /* _XENOMAI_ALCHEMY_PIPE_H */ diff --git a/lib/alchemy/Makefile.am b/lib/alchemy/Makefile.am index 4632394..2f6a4ea 100644 --- a/lib/alchemy/Makefile.am +++ b/lib/alchemy/Makefile.am @@ -28,6 +28,12 @@ libalchemy_la_SOURCES = \ timer.c \ timer.h +if XENO_COBALT +libalchemy_la_SOURCES += \ + pipe.c \ + pipe.h +endif + libalchemy_la_CPPFLAGS = \ @XENO_USER_CFLAGS@ \ -I$(top_srcdir)/include \ diff --git a/lib/alchemy/Makefile.in b/lib/alchemy/Makefile.in index 43be5b4..c46ebc5 100644 --- a/lib/alchemy/Makefile.in +++ b/lib/alchemy/Makefile.in @@ -35,6 +35,10 @@ POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ +@XENO_COBALT_TRUE@am__append_1 = \ +@XENO_COBALT_TRUE@ pipe.c \ +@XENO_COBALT_TRUE@ pipe.h + subdir = lib/alchemy DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in COPYING ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 @@ -76,13 +80,18 @@ am__base_list = \ am__installdirs = "$(DESTDIR)$(libdir)" LTLIBRARIES = $(lib_LTLIBRARIES) libalchemy_la_LIBADD = +am__libalchemy_la_SOURCES_DIST = init.c internal.c internal.h \ + reference.h alarm.c alarm.h buffer.c buffer.h cond.c cond.h \ + event.c event.h heap.c heap.h mutex.c mutex.h queue.c queue.h \ + task.c task.h sem.c sem.h timer.c timer.h pipe.c pipe.h +@XENO_COBALT_TRUE@am__objects_1 = libalchemy_la-pipe.lo am_libalchemy_la_OBJECTS = libalchemy_la-init.lo \ libalchemy_la-internal.lo libalchemy_la-alarm.lo \ libalchemy_la-buffer.lo libalchemy_la-cond.lo \ libalchemy_la-event.lo libalchemy_la-heap.lo \ libalchemy_la-mutex.lo libalchemy_la-queue.lo \ libalchemy_la-task.lo libalchemy_la-sem.lo \ - libalchemy_la-timer.lo + libalchemy_la-timer.lo $(am__objects_1) libalchemy_la_OBJECTS = $(am_libalchemy_la_OBJECTS) libalchemy_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ @@ -101,7 +110,7 @@ LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ SOURCES = $(libalchemy_la_SOURCES) -DIST_SOURCES = $(libalchemy_la_SOURCES) +DIST_SOURCES = $(am__libalchemy_la_SOURCES_DIST) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) @@ -264,32 +273,10 @@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ lib_LTLIBRARIES = libalchemy.la libalchemy_la_LDFLAGS = -version-info 0:0:0 -lpthread -libalchemy_la_SOURCES = \ - init.c \ - internal.c \ - internal.h \ - reference.h \ - alarm.c \ - alarm.h \ - buffer.c \ - buffer.h \ - cond.c \ - cond.h \ - event.c \ - event.h \ - heap.c \ - heap.h \ - mutex.c \ - mutex.h \ - queue.c \ - queue.h \ - task.c \ - task.h \ - sem.c \ - sem.h \ - timer.c \ - timer.h - +libalchemy_la_SOURCES = init.c internal.c internal.h reference.h \ + alarm.c alarm.h buffer.c buffer.h cond.c cond.h event.c \ + event.h heap.c heap.h mutex.c mutex.h queue.c queue.h task.c \ + task.h sem.c sem.h timer.c timer.h $(am__append_1) libalchemy_la_CPPFLAGS = \ @XENO_USER_CFLAGS@ \ -I$(top_srcdir)/include \ @@ -379,6 +366,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libalchemy_la-init.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libalchemy_la-internal.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libalchemy_la-mutex.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libalchemy_la-pipe.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libalchemy_la-queue.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libalchemy_la-sem.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libalchemy_la-task.Plo@am__quote@ @@ -489,6 +477,13 @@ libalchemy_la-timer.lo: timer.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libalchemy_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libalchemy_la-timer.lo `test -f 'timer.c' || echo '$(srcdir)/'`timer.c +libalchemy_la-pipe.lo: pipe.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libalchemy_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libalchemy_la-pipe.lo -MD -MP -MF $(DEPDIR)/libalchemy_la-pipe.Tpo -c -o libalchemy_la-pipe.lo `test -f 'pipe.c' || echo '$(srcdir)/'`pipe.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libalchemy_la-pipe.Tpo $(DEPDIR)/libalchemy_la-pipe.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='pipe.c' object='libalchemy_la-pipe.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libalchemy_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libalchemy_la-pipe.lo `test -f 'pipe.c' || echo '$(srcdir)/'`pipe.c + mostlyclean-libtool: -rm -f *.lo diff --git a/lib/alchemy/pipe.c b/lib/alchemy/pipe.c new file mode 100644 index 0000000..604c103 --- /dev/null +++ b/lib/alchemy/pipe.c @@ -0,0 +1,291 @@ +/* + * Copyright (C) 2011 Philippe Gerum <r...@xenomai.org>. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include <unistd.h> +#include <errno.h> +#include <string.h> +#include <fcntl.h> +#include "rtdm/rtipc.h" +#include "copperplate/threadobj.h" +#include "copperplate/heapobj.h" +#include "copperplate/cluster.h" +#include "reference.h" +#include "internal.h" +#include "pipe.h" +#include "timer.h" + +struct syncluster alchemy_pipe_table; + +static struct alchemy_namegen pipe_namegen = { + .prefix = "pipe", + .length = sizeof ((struct alchemy_pipe *)0)->name, +}; + +static struct alchemy_pipe *find_alchemy_pipe(RT_PIPE *pipe, int *err_r) +{ + struct alchemy_pipe *pcb; + + if (pipe == NULL || ((intptr_t)pipe & (sizeof(intptr_t)-1)) != 0) + goto bad_handle; + + pcb = mainheap_deref(pipe->handle, struct alchemy_pipe); + if (pcb == NULL || ((intptr_t)pcb & (sizeof(intptr_t)-1)) != 0) + goto bad_handle; + + if (pcb->magic == ~pipe_magic) + goto dead_handle; + + if (pcb->magic == pipe_magic) + return pcb; +bad_handle: + *err_r = -EINVAL; + return NULL; + +dead_handle: + /* Removed under our feet. */ + *err_r = -EIDRM; + return NULL; +} + +int rt_pipe_create(RT_PIPE *pipe, + const char *name, int minor, size_t poolsize) +{ + struct rtipc_port_label plabel; + struct sockaddr_ipc saddr; + struct alchemy_pipe *pcb; + struct service svc; + size_t streambufsz; + int ret = 0, sock; + + if (threadobj_irq_p()) + return -EPERM; + + COPPERPLATE_PROTECT(svc); + + pcb = xnmalloc(sizeof(*pcb)); + if (pcb == NULL) { + COPPERPLATE_UNPROTECT(svc); + return -ENOMEM; + } + + alchemy_build_name(pcb->name, name, &pipe_namegen); + + if (syncluster_addobj(&alchemy_pipe_table, pcb->name, &pcb->cobj)) { + xnfree(pcb); + COPPERPLATE_UNPROTECT(svc); + return -EEXIST; + } + + sock = __RT(socket(AF_RTIPC, SOCK_DGRAM, IPCPROTO_XDDP)); + if (sock < 0) { + ret = -errno; + xnfree(pcb); + goto out; + } + + if (name && *name) { + strncpy(plabel.label, name, sizeof(plabel.label)-1); + plabel.label[sizeof(plabel.label)-1] = '\0'; + ret = __RT(setsockopt(sock, SOL_XDDP, XDDP_LABEL, + &plabel, sizeof(plabel))); + if (ret) + goto fail; + } + + if (poolsize > 0) { + ret = setsockopt(pcb->sock, SOL_XDDP, XDDP_POOLSZ, + &poolsize, sizeof(poolsize)); + if (ret) + goto fail; + } + + streambufsz = ALCHEMY_PIPE_STREAMSZ; + ret = __RT(setsockopt(pcb->sock, SOL_XDDP, XDDP_BUFSZ, + &streambufsz, streambufsz)); + if (ret) + goto fail; + + memset(&saddr, 0, sizeof(saddr)); + saddr.sipc_family = AF_RTIPC; + saddr.sipc_port = minor; + ret = bind(sock, (struct sockaddr *)&saddr, sizeof(saddr)); + if (ret) + goto fail; + + pcb->sock = sock; + pcb->magic = pipe_magic; + pipe->handle = mainheap_ref(pcb, uintptr_t); +out: + COPPERPLATE_UNPROTECT(svc); + + return 0; +fail: + ret = -errno; + __RT(close(sock)); + syncluster_delobj(&alchemy_pipe_table, &pcb->cobj); + xnfree(pcb); + + COPPERPLATE_UNPROTECT(svc); + + return ret; +} + +int rt_pipe_delete(RT_PIPE *pipe) +{ + struct alchemy_pipe *pcb; + struct service svc; + int ret = 0; + + if (threadobj_irq_p()) + return -EPERM; + + COPPERPLATE_PROTECT(svc); + + pcb = find_alchemy_pipe(pipe, &ret); + if (pcb == NULL) + goto out; + + ret = __RT(close(pcb->sock)); + if (ret) { + ret = -errno; + if (ret == -EBADF) + ret = -EIDRM; + goto out; + } + + syncluster_delobj(&alchemy_pipe_table, &pcb->cobj); + pcb->magic = ~pipe_magic; +out: + COPPERPLATE_UNPROTECT(svc); + + return ret; +} + +ssize_t rt_pipe_read_until(RT_PIPE *pipe, + void *buf, size_t size, RTIME timeout) +{ + struct timeval tv = { .tv_sec = 0, .tv_usec = 0 }; + struct timespec ts, *timespec; + struct alchemy_pipe *pcb; + struct service svc; + int err, flags; + ssize_t ret; + + if (!threadobj_current_p()) + return -EPERM; + + COPPERPLATE_PROTECT(svc); + + pcb = find_alchemy_pipe(pipe, &err); + if (pcb == NULL) { + ret = err; + goto out; + } + + switch (timeout) { + default: + timespec = alchemy_get_timespec(timeout, &ts); + tv.tv_sec = ts.tv_sec; + tv.tv_usec = ts.tv_nsec / 1000; + /* Falldown wanted. */ + case TM_INFINITE: + __RT(setsockopt(pcb->sock, SOL_SOCKET, + SO_RCVTIMEO, &tv, sizeof(tv))); + flags = 0; + break; + case TM_NONBLOCK: + flags = MSG_DONTWAIT; + break; + } + + ret = __RT(recvfrom(pcb->sock, buf, size, flags, NULL, 0)); + if (ret < 0) + ret = -errno; +out: + COPPERPLATE_UNPROTECT(svc); + + return ret; +} + +ssize_t rt_pipe_read(RT_PIPE *pipe, + void *buf, size_t size, RTIME timeout) +{ + timeout = alchemy_rel2abs_timeout(timeout); + return rt_pipe_read_until(pipe, buf, size, timeout); +} + +static ssize_t do_write_pipe(RT_PIPE *pipe, + const void *buf, size_t size, int flags) +{ + struct alchemy_pipe *pcb; + struct service svc; + ssize_t ret; + int err; + + if (threadobj_irq_p()) + return -EPERM; + + COPPERPLATE_PROTECT(svc); + + pcb = find_alchemy_pipe(pipe, &err); + if (pcb == NULL) { + ret = err; + goto out; + } + + ret = __RT(sendto(pcb->sock, buf, size, flags, NULL, 0)); + if (ret < 0) + ret = -errno; +out: + COPPERPLATE_UNPROTECT(svc); + + return ret; +} + +ssize_t rt_pipe_write(RT_PIPE *pipe, + const void *buf, size_t size, int mode) +{ + int flags = 0; + + if (mode & P_URGENT) + flags |= MSG_OOB; + + return do_write_pipe(pipe, buf, size, flags); +} + +ssize_t rt_pipe_stream(RT_PIPE *pipe, + const void *buf, size_t size) +{ + return do_write_pipe(pipe, buf, size, MSG_MORE); +} + +int rt_pipe_bind(RT_PIPE *pipe, + const char *name, RTIME timeout) +{ + return alchemy_bind_object(name, + &alchemy_pipe_table, + timeout, + offsetof(struct alchemy_pipe, cobj), + &pipe->handle); +} + +int rt_pipe_unbind(RT_PIPE *pipe) +{ + pipe->handle = 0; + return 0; +} diff --git a/lib/alchemy/pipe.h b/lib/alchemy/pipe.h new file mode 100644 index 0000000..1cfb6c0 --- /dev/null +++ b/lib/alchemy/pipe.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2011 Philippe Gerum <r...@xenomai.org>. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _ALCHEMY_PIPE_H +#define _ALCHEMY_PIPE_H + +#include <copperplate/cluster.h> +#include <alchemy/pipe.h> + +/* Fixed default for MSG_MORE accumulation. */ +#define ALCHEMY_PIPE_STREAMSZ 16384 + +struct alchemy_pipe { + unsigned int magic; /* Must be first. */ + char name[32]; + int sock; + struct clusterobj cobj; +}; + +#define pipe_magic 0x8b8bebeb + +#endif /* _ALCHEMY_PIPE_H */ _______________________________________________ Xenomai-git mailing list Xenomai-git@gna.org https://mail.gna.org/listinfo/xenomai-git