Commit b1aae16b authored by Aurelio Colosimo's avatar Aurelio Colosimo Committed by Alessandro Rubini

arch-wrs: copy mini-rpc module from its git repository

mini-rpc is a copy of commit 4c87062d from
repository git://github.com/a-rubini/mini-rpc.gitSigned-off-by: Aurelio Colosimo's avatarAurelio Colosimo <aurelio@aureliocolosimo.it>
parent c232328f
This diff is collapsed.
AS = $(CROSS_COMPILE)as
LD = $(CROSS_COMPILE)ld
CC = $(CROSS_COMPILE)gcc
CPP = $(CC) -E
AR = $(CROSS_COMPILE)ar
NM = $(CROSS_COMPILE)nm
STRIP = $(CROSS_COMPILE)strip
OBJCOPY = $(CROSS_COMPILE)objcopy
OBJDUMP = $(CROSS_COMPILE)objdump
CFLAGS = -Wall -ggdb -O2 -fno-strict-aliasing
LDFLAGS = -L. -lminipc -lm
# We need to support freestading environments: an embedded CPU that
# sits as a server on its own memory are and awaits commands
# The user can pass IPC_FREESTANDING=y
IPC_FREESTANDING ?= $(shell ./check-freestanding $(CC))
IPC_HOSTED ?= $(shell ./check-freestanding -n $(CC))
# Hosted is the opposite of freestanding, and cflags change too
ifeq ($(IPC_FREESTANDING),y)
IPC_HOSTED = n
CFLAGS += -ffreestanding -Iarch-$(ARCH)
else
IPC_HOSTED = y
endif
OBJ-$(IPC_HOSTED) = minipc-core.o minipc-server.o minipc-client.o
OBJ-$(IPC_FREESTANDING) = minipc-mem-server.o
LIB = libminipc.a
# export these to the examples (but if you make there IPC_HOSTED is default
export IPC_FREESTANDING IPC_HOSTED
all: $(LIB)
$(MAKE) -C examples
$(LIB): $(OBJ-y)
$(AR) r $@ $^
# the default puts LDFLAGS too early. Bah...
%: %.c
$(CC) $(CFLAGS) $^ $(LDFLAGS) -o $@
# This is stupid, it won't apply the first time, but, well... it works
$(wildcard *.o): $(wildcard *.h)
clean:
rm -f *.o *~ $(LIB)
$(MAKE) -C examples clean
install:
@echo "We have no install rule by now"
All documentation is now under the doc/ directory.
The input file is called doc/mini-ipc.in (it is readable by itself).
To have all usual output formats you can run "make" withing ./doc
but you need TexInfo installed.
#ifndef __ARCH_LM32_STDINT_H__
#define __ARCH_LM32_STDINT_H__
/*
* We miss a stdint.h in our compiler, so provide some types here,
* knowing the CPU is 32-bits and uses LP32 model
*/
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned long uint32_t;
typedef signed char int8_t;
typedef signed short int16_t;
typedef signed long int32_t;
#endif /* __ARCH_LM32_STDINT_H__ */
#!/bin/sh
# I used to just check __STDC_HOSTED__ without special CFLAGS, but now I
# want to force freestanding compilation on otherwise hosted processors.
# Thus, the user can set IPC_FREESTANDING=y . If unset, this gets called.
# Accept "-n" to invert the result (select second field, not first)
if [ "x$1" = "x-n" ]; then select=2; shift; else select=1; fi
CC=$1
if [ "x$CC" = "x" ]; then
echo "$0: pass the compiler path (\$CC) as argument" >& 2
exit 1
fi
# Check the compiler: if it has no matches is prints the unadorned string
if [ "$($CC -print-file-name=libc.so)" = "libc.so" ]; then
res=y,n
else
res=n,y
fi
# If passed from the user, override the autodetected value
if [ "$IPC_FREESTANDING" = "y" ]; then
res=y,n
fi
echo $res | cut -d, -f $select
*~
*.aux
*.cp
*.fn
*.html
*.info
*.ky
*.log
*.pdf
*.pg
*.texi
*.toc
*.tp
*.txt
*.vr
#
# Makefile for the documentation directory
#
# Copyright 1994,2000,2010,2011 Alessandro Rubini <rubini@linux.it>
#
#################
# There is not basenames here, all *.in are considered input
INPUT = $(wildcard *.in)
TEXI = $(INPUT:.in=.texi)
INFO = $(INPUT:.in=.info)
HTML = $(INPUT:.in=.html)
TXT = $(INPUT:.in=.txt)
PDF = $(INPUT:.in=.pdf)
ALL = $(INFO) $(HTML) $(TXT) $(PDF)
MAKEINFO ?= makeinfo
%.texi: %.in
@rm -f $@
sed -f ./infofilter $< > $@
emacs -batch --no-site-file -l fixinfo $@
chmod -w $@
%.pdf: %.texi
texi2pdf --batch $<
%.info: %.texi
$(MAKEINFO) $< -o $@
%.html: %.texi
$(MAKEINFO) --html --no-split -o $@ $<
%.txt: %.texi
$(MAKEINFO) --no-headers $< > $@
##############################################
.PHONY: all images check terse clean install
.INTERMEDIATE: $(TEXI)
all: images $(ALL)
$(MAKE) terse
images::
if [ -d images ]; then $(MAKE) -C images || exit 1; fi
check: _err.ps
gs -sDEVICE=linux -r320x200x16 $<
terse:
for n in cp fn ky pg toc tp vr aux log; do rm -f *.$$n; done
rm -f *~
clean: terse
rm -f $(ALL) $(TEXI)
install:
;; use:
;; emacs -batch -l ./fixinfo.el <file>
;; or, better:
;; emacs -batch --no-site-file -l ./fixinfo.el <file>
(defun fixinfo (file)
(find-file-other-window file)
(message (concat "Maxing texinfo tree in " file))
(texinfo-all-menus-update)
(texinfo-every-node-update)
(save-buffer)
(kill-buffer (current-buffer))
)
;; loop over command line arguments
(mapcar 'fixinfo command-line-args-left)
(kill-emacs)
#! /usr/bin/sed -f
# allow "%" as a comment char, but only at the beginning of the line
s/^%/@c /
#s/[^\\]%.*$//
s/^\\%/%/
#preserve blanks and braces in @example blocks
/@example/,/@end example/ s/{/@{/g
/@example/,/@end example/ s/}/@}/g
/@example/,/@end example/ p
/@example/,/@end example/ d
/@smallexample/,/@end smallexample/ s/{/@{/g
/@smallexample/,/@end smallexample/ s/}/@}/g
/@smallexample/,/@end smallexample/ p
/@smallexample/,/@end smallexample/ d
# remove leading blanks
s/^[ ]*//
This diff is collapsed.
trivial-server
trivial-client
pty-server
pty-client
mbox-bridge
mbox-client
mbox-process
shmem-server
shmem-client
freestanding-server
# examples for mini-rpc; depends on ..
AS = $(CROSS_COMPILE)as
LD = $(CROSS_COMPILE)ld
CC = $(CROSS_COMPILE)gcc
CPP = $(CC) -E
AR = $(CROSS_COMPILE)ar
NM = $(CROSS_COMPILE)nm
STRIP = $(CROSS_COMPILE)strip
OBJCOPY = $(CROSS_COMPILE)objcopy
OBJDUMP = $(CROSS_COMPILE)objdump
CFLAGS = -Wall -ggdb -I.. -O2
LDFLAGS = -L.. -lminipc -lm
# we may be hosted or freestanding. For freestanding there is one
# example only. The following variables are exported by the upper
# Makefile, but if you "make" in this directory, it checks by itself
IPC_FREESTANDING ?= $(shell ../check-freestanding $(CC))
IPC_HOSTED ?= $(shell ../check-freestanding -n $(CC))
# Hosted is the opposite of freestanding, and cflags change too
ifeq ($(IPC_FREESTANDING),y)
IPC_HOSTED = n
CFLAGS += -ffreestanding -I../arch-$(ARCH)
else
IPC_HOSTED = y
endif
PROGS-$(IPC_HOSTED) = trivial-server trivial-client
PROGS-$(IPC_HOSTED) += pty-server pty-client
PROGS-$(IPC_HOSTED) += mbox-process mbox-bridge mbox-client
PROGS-$(IPC_HOSTED) += shmem-server shmem-client
IPC_FREESTANDING ?= n
PROGS-$(IPC_FREESTANDING) += freestanding-server
all: $(PROGS-y)
# the default puts LDFLAGS too early. Bah...
%: %.c
$(CC) $(CFLAGS) $^ $(LDFLAGS) -o $@
pty-server: pty-server.o pty-rpc_server.o pty-rpc_structs.o
$(CC) $(CFLAGS) $^ $(LDFLAGS) -lutil -o $@
pty-client: pty-client.o pty-rpc_structs.o
$(CC) $(CFLAGS) $^ $(LDFLAGS) -o $@
shmem-server: shmem-server.o shmem-structs.o
$(CC) $(CFLAGS) $^ $(LDFLAGS) -o $@
shmem-client: shmem-client.o shmem-structs.o
$(CC) $(CFLAGS) $^ $(LDFLAGS) -o $@
# This is stupid, it won't apply the first time, but, well... it works
$(PROGS-y) $(wildcard *.o): $(wildcard ../*.h ../*.a)
clean:
rm -f *.o *~ $(PROGS)
All documentation is now under the ../doc/ directory.
The input file is called doc/mini-ipc.in (it is readable by itself).
To have all usual output formats you can run "make" withing ./doc
but you need TexInfo installed.
/*
* Mini-ipc: an example freestanding server, based in memory
*
* Copyright (C) 2011,2012 CERN (www.cern.ch)
* Author: Alessandro Rubini <rubini@gnudd.com>
*
* This code is copied from trivial-server, and made even more trivial
*/
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include "minipc.h"
/* A function that ignores the RPC and is written normally */
static int ss_do_sum(int a, int b)
{
return a + b;
}
/* The following ones are RPC-aware */
static int ss_sum_function(const struct minipc_pd *pd,
uint32_t *args, void *ret)
{
int i;
i = ss_do_sum(args[0], args[1]);
*(int *)ret = i;
return 0;
}
static int ss_mul_function(const struct minipc_pd *pd,
uint32_t *args, void *ret)
{
int a, b;
a = *(int *)args;
b = *(int *)(args + 1);
*(int *)ret = a * b;
return 0;
}
/* Describe the two functions above */
const struct minipc_pd ss_sum_struct = {
.f = ss_sum_function,
.name = "sum",
.retval = MINIPC_ARG_ENCODE(MINIPC_ATYPE_INT, int),
.args = {
MINIPC_ARG_ENCODE(MINIPC_ATYPE_INT, int),
MINIPC_ARG_ENCODE(MINIPC_ATYPE_INT, int),
MINIPC_ARG_END,
},
};
const struct minipc_pd ss_mul_struct = {
.f = ss_mul_function,
.name = "mul",
.retval = MINIPC_ARG_ENCODE(MINIPC_ATYPE_INT, int),
.args = {
MINIPC_ARG_ENCODE(MINIPC_ATYPE_INT, int),
MINIPC_ARG_ENCODE(MINIPC_ATYPE_INT, int),
MINIPC_ARG_END,
},
};
int main(int argc, char **argv)
{
struct minipc_ch *server;
server = minipc_server_create("mem:f000", 0);
if (!server)
return 1;
minipc_export(server, &ss_sum_struct);
minipc_export(server, &ss_mul_struct);
while (1) {
/* do something else... */
minipc_server_action(server, 1000);
}
}
/*
* Example bridge beteen mini-ipc and a mailbox memory area
*
* Copyright (C) 2011 CERN (www.cern.ch)
* Author: Alessandro Rubini <rubini@gnudd.com>
*
* Released in the public domain
*/
/*
* This example uses a shared memory area to talk with mbox-process.
* The same technique can be used to communicate with an os-less
* soft-core within an FPGA, and actually this is the reason why I'm
* writing this demo.
*
* The bridge can export functions in both ways: as a mini-ipc server
* it exports "stat", and as a client it calls gettimeofday in the
* trivial-server.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/shm.h>
#include <sys/select.h>
#include "minipc.h"
#include "minipc-shmem.h" /* The shared data structures */
struct minipc_mbox_info *info; /* unfortunately global... */
/* This function implements the "stat" mini-ipc server, by asking mbox */
static int mb_stat_server(const struct minipc_pd *pd,
uint32_t *args, void *ret)
{
char *fname = (void *)args;
/* pass this to the shmem */
memset(info->fname, 0, sizeof(info->fname));
strncpy(info->fname, fname, sizeof(info->fname) -1 );
/* ask and wait */
info->bridge_req = 1;
while (info->bridge_req)
usleep(1000);
memcpy(ret, &info->stbuf, sizeof(info->stbuf));
return 0;
}
/* The description here is the same as in the server */
const struct minipc_pd mb_tod_struct = {
.name = "gettimeofday",
.retval = MINIPC_ARG_ENCODE(MINIPC_ATYPE_STRUCT, struct timeval),
.args = {
MINIPC_ARG_END,
},
};
/* And here it's the same as in the client */
struct minipc_pd mb_stat_struct = {
.f = mb_stat_server,
.name = "stat",
.retval = MINIPC_ARG_ENCODE(MINIPC_ATYPE_STRUCT, struct stat),
.args = {
MINIPC_ARG_ENCODE(MINIPC_ATYPE_STRING, char *),
MINIPC_ARG_ENCODE(MINIPC_ATYPE_STRING, char *),
MINIPC_ARG_END,
},
};
/* No arguments */
int main(int argc, char **argv)
{
struct minipc_ch *server;
struct minipc_ch *client;
void *shmem;
int ret;
if (argc > 1) {
fprintf(stderr, "%s: no arguments please\n", argv[0]);
exit(1);
}
/* Create your shared memory and/or attach to it */
ret = shmget(MINIPC_SHM, sizeof(struct minipc_mbox_info),
IPC_CREAT | 0666);
if (ret < 0) {
fprintf(stderr, "%s: shmget(): %s\n", argv[0],
strerror(errno));
exit(1);
}
shmem = shmat(ret, NULL, SHM_RND);
if (shmem == (void *)-1) {
fprintf(stderr, "%s: shmat(): %s\n", argv[0],
strerror(errno));
exit(1);
}
info = shmem;
/* Create a server socket for mini-ipc */
server = minipc_server_create("mbox", 0);
if (!server) {
fprintf(stderr, "%s: server_create(): %s\n", argv[0],
strerror(errno));
exit(1);
}
minipc_set_logfile(server, stderr);
minipc_export(server, &mb_stat_struct);
/* Connect as a client to the trivial-server */
client = minipc_client_create("trivial", 0);
if (!client) {
fprintf(stderr, "%s: client_create(): %s\n", argv[0],
strerror(errno));
exit(1);
}
/* Loop serving both mini-ipc and the mailbox */
while (1) {
fd_set set;
struct timeval to = {
MBOX_POLL_US / (1000*1000),
MBOX_POLL_US % (1000*1000)
};
minipc_server_get_fdset(server, &set);
/* Wait for any server, with the defined timeout */
ret = select(16 /* hack */, &set, NULL, NULL, &to);
if (ret > 0) {
if (minipc_server_action(server, 0) < 0) {
fprintf(stderr, "%s: server_action(): %s\n",
argv[0], strerror(errno));
exit(1);
}
}
/* No IPC request: if needed act as IPC client */
if (info->proc_req) {
memset(&info->tv, 0, sizeof(info->tv));
minipc_call(client, 100 /* ms */,
&mb_tod_struct, &info->tv, NULL);
info->proc_req = 0;
}
}
}
/*
* Example mbox client
*
* Copyright (C) 2011 CERN (www.cern.ch)
* Author: Alessandro Rubini <rubini@gnudd.com>
*
* Released in the public domain
*
* This process requests "stat" calls to the mbox-bridge, which in turn
* asks it to the "remote" process that lives behing an mbox (shmem).
* The program reads filenames from stdin, in order to allow several clients
* connected to the same bridge.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/time.h>
#include <sys/stat.h>
#include "minipc.h"
#define CLIENT_TIMEOUT 100 /* ms */
/* The description here is the same as in the server */
struct minipc_pd rpc_stat = {
.name = "stat",
.retval = MINIPC_ARG_ENCODE(MINIPC_ATYPE_STRUCT, struct stat),
.args = {
MINIPC_ARG_ENCODE(MINIPC_ATYPE_STRING, char *),
MINIPC_ARG_ENCODE(MINIPC_ATYPE_STRING, char *),
MINIPC_ARG_END,
},
};
int main(int argc, char **argv)
{
struct minipc_ch *client;
struct stat stbuf;
int ret;
char s[80];
client = minipc_client_create("mbox", 0);
if (!client) {
fprintf(stderr, "%s: client_create(): %s\n", argv[0],
strerror(errno));
exit(1);
}
minipc_set_logfile(client, stderr);
while (fgets(s, sizeof(s), stdin)) {
/* strip trailing newline */
s[strlen(s)-1] = '\0';
ret = minipc_call(client, CLIENT_TIMEOUT, &rpc_stat,
&stbuf, s);
if (ret < 0) {
fprintf(stderr, "stat(%s): %s\n", s, strerror(errno));
continue;
}
printf("%s:\n", s);
printf("mode %o, size %li, owner %i, atime %li\n",
stbuf.st_mode, (long)stbuf.st_size, stbuf.st_uid,
stbuf.st_atime);
}
return 0;
}
/*
* Example process connected to the world through a mailbox
*
* Copyright (C) 2011 CERN (www.cern.ch)
* Author: Alessandro Rubini <rubini@gnudd.com>
*
* Released in the public domain
*/
/*
* This example uses a shared memory area to talk with the mbox-bridge.
* In my real-world application this will be an os-less
* soft-core within an FPGA.
*
* The process is both a server and a client. As a server iIt replies
* to "stat" calls coming from the bridge process; as a client it asks
* the time of day once a second or so.
*
* It doesn't need minipc.h because it is not directly connected to the ipc
* mechanism
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "minipc-shmem.h" /* The shared data structures */
struct minipc_mbox_info *info; /* unfortunately global... */
/* No arguments */
int main(int argc, char **argv)
{
void *shmem;
int ret, i;
if (argc > 1) {
fprintf(stderr, "%s: no arguments please\n", argv[0]);
exit(1);
}
/* Create your shared memory and/or attach to it */
ret = shmget(MINIPC_SHM, sizeof(struct minipc_mbox_info),
IPC_CREAT | 0666);
if (ret < 0) {
fprintf(stderr, "%s: shmget(): %s\n", argv[0],
strerror(errno));
exit(1);
}
shmem = shmat(ret, NULL, SHM_RND);
if (shmem == (void *)-1) {
fprintf(stderr, "%s: shmat(): %s\n", argv[0],
strerror(errno));
exit(1);
}
info = shmem;
/* Loop forever */
for (i = 0; 1; i++) {
if (info->bridge_req) {
/* We got a request: serve it */
printf("Serving stat(%s)\n", info->fname);
memset(&info->stbuf, 0, sizeof(info->stbuf));
stat(info->fname, &info->stbuf);
info->bridge_req = 0;
}
if (i * MBOX_POLL_US >= 1000 * 1000) {
/* 1s passed, ask for the date */
info->proc_req = 1;
while (info->proc_req)
;
printf("time: %li.%06li\n", (long)info->tv.tv_sec,
(long)info->tv.tv_usec);
i = 0;
}
usleep(MBOX_POLL_US);
}
}
#ifndef __MINIPC_SHMEM_H__
#define __MINIPC_SHMEM_H__
#include <sys/stat.h>
#include <sys/time.h>
#define MINIPC_SHM 0x3465 /* Random */
struct minipc_mbox_info {
volatile int bridge_req; /* A request is asked by the bridge */
volatile int proc_req; /* A request is asked by the process */
/* The bridge can ask "stat" to the bare process */
char fname[64];
struct stat stbuf;
/* The bare process can ask timeofday to the bridge */
struct timeval tv;