Changed directory structure

* silverfish is a submodule now
* memory modules from silverfish runtime is copied in to the aWsm runtime.
* runtime/tests/Makefile compiles different tests and silverfish/code_benches..
master
phani 6 years ago
parent b2d0ecc66f
commit 9b0ec6f7dc

4
.gitignore vendored

@ -50,3 +50,7 @@ modules.order
Module.symvers
Mkfile.old
dkms.conf
runtime/tags
runtime/bin
runtime/tests/tmp/

7
.gitmodules vendored

@ -0,0 +1,7 @@
[submodule "silverfish"]
path = silverfish
url = https://github.com/gwsystems/silverfish.git
ignore = dirty
[submodule "runtime/jsmn"]
path = runtime/jsmn
url = https://github.com/zserge/jsmn.git

@ -0,0 +1,74 @@
# Inspired by lucet's Dockerfile.
# using ubuntu 18 docker image
FROM ubuntu:bionic
# install some basic packages
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
build-essential \
curl \
git \
python3-dev \
python3-pip \
cmake \
ca-certificates \
libssl-dev \
pkg-config \
gcc \
g++ \
clang-6.0 \
clang-tools-6.0 \
llvm-6.0 \
llvm-6.0-dev \
libc++-dev \
libc++abi-dev \
lld-6.0 \
lldb-6.0 \
libclang-6.0-dev \
libclang-common-6.0-dev \
vim \
apache2 \
subversion \
libapache2-mod-svn \
libsvn-dev \
binutils-dev \
build-essential \
automake \
libtool \
strace \
less \
libuv1-dev \
&& rm -rf /var/lib/apt/lists/*
# Enable apache2 for svn
RUN a2enmod dav
RUN a2enmod dav_svn
RUN service apache2 restart
RUN pip3 install numpy
# set to use our installed clang version
RUN update-alternatives --install /usr/bin/clang clang /usr/bin/clang-6.0 100
RUN update-alternatives --install /usr/bin/llvm-config llvm-config /usr/bin/llvm-config-6.0 100
# set LD_LIBRARY_PATH
ENV LD_LIBRARY_PATH=/usr/local/lib
# install rust - commands copied straight from lucet's dockerfile.
# so we have exactly the same rust version as lucet!
RUN curl -sS -L -O https://static.rust-lang.org/dist/rust-1.35.0-x86_64-unknown-linux-gnu.tar.gz \
&& tar xzf rust-1.35.0-x86_64-unknown-linux-gnu.tar.gz \
&& cd rust-1.35.0-x86_64-unknown-linux-gnu \
&& ./install.sh \
&& cd .. \
&& rm -rf rust-1.35.0-x86_64-unknown-linux-gnu rust-1.35.0-x86_64-unknown-linux-gnu.tar.gz
ENV PATH=/usr/local/bin:$PATH
RUN cargo install --root /usr/local cargo-audit cargo-watch
## copied again from lucet for when we want to use wasi-sdk
#RUN curl -sS -L -O https://github.com/CraneStation/wasi-sdk/releases/download/wasi-sdk-5/wasi-sdk_5.0_amd64.deb \
# && dpkg -i wasi-sdk_5.0_amd64.deb && rm -f wasi-sdk_5.0_amd64.deb
#
#ENV WASI_SDK=/opt/wasi-sdk
ENV PATH=/opt/awsm/bin:$PATH

@ -0,0 +1,38 @@
SFCC='silverfish'
ROOT=${ROOT:-$(cd "$(dirname ${BASH_SOURCE:-$0})" && pwd)}
.PHONY: build
build:
@echo "Building wasmception toolchain, takes a while."
@cd ${SFCC} && make -C wasmception && cd ${ROOT}
@echo "Building silverfish compiler (release)"
@cd ${SFCC} && cargo build --release && cd ${ROOT}
.PHONY: build-dev
build-dev:
@echo "Building wasmception toolchain, takes a while."
@cd ${SFCC} && make -C wasmception && cd ${ROOT}
@echo "Building silverfish compiler (default==debug)"
@cd ${SFCC} && cargo build && cd ${ROOT}
.PHONY: clean
clean:
@echo "Cleaning silverfish compiler"
@cd ${SFCC} && cargo clean && cd ${ROOT}
# wasmception is too slow to recompile,
# so lets not make that part of the "silverfish" cleanup
.PHONY: wclean
wclean:
@echo "Cleaning wasmception toolchain"
@cd ${SFCC} && make -C wasmception clean && cd ${ROOT}
.PHONY: runtime
runtime:
@echo "Building runtime!"
make -C runtime
.PHONY: install
install: build
@./install.sh wasmception

@ -0,0 +1,144 @@
#!/bin/sh
#
# This environment file and dockerfile are
# inspired by lucet's devenv_xxx.sh scripts
#
HOST_ROOT=${HOST_ROOT:-$(cd "$(dirname ${BASH_SOURCE:-$0})" && pwd)}
SYS_NAME='awsm'
HOST_SYS_MOUNT=${HOST_SYS_MOUNT:-"/${SYS_NAME}"}
SYS_WASMCEPTION='silverfish/wasmception'
SYS_DOC_NAME=${SYS_NAME}
SYS_DOC_DEVNAME=${SYS_DOC_NAME}'-dev'
SYS_DOC_TAG='latest'
SYS_DOC_NAMETAG=${SYS_DOC_NAME}:${SYS_DOC_TAG}
SYS_DOC_DEVNAMETAG=${SYS_DOC_DEVNAME}:${SYS_DOC_TAG}
SYS_BUILD_TIMEOUT=10
usage()
{
echo "usage $0 <setup/run/stop>"
}
countdown()
{
tmp_cnt=$1
while [ ${tmp_cnt} -gt 0 ]; do
printf "${tmp_cnt}."
# sleep 1
tmp_cnt=$((tmp_cnt - 1))
done
echo
}
envsetup()
{
if docker image inspect ${SYS_DOC_NAMETAG} > /dev/null; then
echo "${SYS_DOC_NAMETAG} image exists, remove it first!"
exit 1
fi
echo "Setting up ${SYS_NAME}"
git submodule update --init --recursive 2>/dev/null ||:
# Perhaps change in the wasmception (forked) repo,
# Gregor already forked every mainline repo to modify something or the other!
#
# That said, you may comment this if you're not behind a firewall!
# http:// doesn't work for me at my current work place.
echo "Changing http:// to https:// in ${SYS_WASMCEPTION}"
sed -i 's/http:\/\//https:\/\//' ${SYS_WASMCEPTION}/Makefile
if docker image inspect ${SYS_DOC_DEVNAMETAG} >> /dev/null; then
echo "${SYS_DOC_DEVNAME} image exists, rebuilding it"
echo "(you have ${SYS_BUILD_TIMEOUT}secs to stop the rebuild)"
countdown ${SYS_BUILD_TIMEOUT}
fi
echo "Building ${SYS_DOC_DEVNAMETAG}"
docker build -t ${SYS_DOC_DEVNAMETAG} .
echo "Creating ${SYS_DOC_NAMETAG} on top of ${SYS_DOC_DEVNAMETAG}"
docker run --privileged --name=${SYS_DOC_DEVNAME} --detach --mount type=bind,src="$(cd $(dirname ${0}); pwd -P),target=/${SYS_NAME}" \
${SYS_DOC_DEVNAMETAG} /bin/sleep 99999999 > /dev/null
echo "Building ${SYS_NAME}"
docker exec -t -w ${HOST_SYS_MOUNT} ${SYS_DOC_DEVNAME} make install
echo "Tagging the new image"
docker container commit ${SYS_DOC_DEVNAME} ${SYS_DOC_NAMETAG}
echo "Cleaning up ${SYS_DOC_DEVNAME}"
docker kill ${SYS_DOC_DEVNAME}
docker rm ${SYS_DOC_DEVNAME}
echo "Done!"
}
envrun()
{
if ! docker image inspect ${SYS_DOC_NAMETAG} > /dev/null; then
envbuild
fi
if docker ps -f name=${SYS_DOC_NAME} --format '{{.Names}}' | grep -q "^${SYS_DOC_NAME}" ; then
echo "Container is running" >&2
else
echo "Starting ${SYS_DOC_NAME}"
docker run --privileged --security-opt seccomp:unconfined --name=${SYS_DOC_NAME} --detach --mount type=bind,src="$(cd $(dirname ${0}); pwd -P),target=/${SYS_NAME}" \
${SYS_DOC_NAMETAG} /bin/sleep 99999999 > /dev/null
fi
echo "Running shell"
docker exec -t -i -w "${HOST_SYS_MOUNT}" ${SYS_DOC_NAME} /bin/bash
}
envstop()
{
echo "Stopping container"
docker stop ${SYS_DOC_NAME}
echo "Removing container"
docker rm ${SYS_DOC_NAME}
}
envrm()
{
envstop
docker rmi ${SYS_DOC_NAME}
}
envrma()
{
envrm
docker rmi ${SYS_DOC_DEVNAME}
}
if [ $# -ne 1 ]; then
usage $0
exit 1
fi
case $1 in
run)
envrun
;;
stop)
envstop
;;
setup)
envsetup
;;
rm)
envrm
;;
rma)
envrma
;;
*)
echo "invalid option: $1"
usage $0
exit 1
;;
esac
echo
echo "done!"

@ -0,0 +1,77 @@
#!/bin/sh
# Inspired by Lucet's install.sh
echo "Setting up toolchain environment"
SYS_SRC_PREFIX=${SYS_SRC_PREFIX:-"$(
cd $(dirname $(dirname ${0}))
pwd -P
)"}
if [ ! -x "${SYS_SRC_PREFIX}/install.sh" ]; then
echo "Unable to find the install script" >&2
exit 1
fi
SYS_NAME='awsm'
SILVERFISH='silverfish'
SYS_PREFIX=${SYS_PREFIX:-"/opt/${SYS_NAME}"}
SYS_SRC_PREFIX=${SYS_SRC_PREFIX:-"/${SYS_NAME}"}
SYS_SF_REL_DIR=${SYS_SF_REL_DIR:-"${SYS_SRC_PREFIX}/${SILVERFISH}/target/release"}
SYS_BIN_DIR=${SYS_BIN_DIR:-"${SYS_PREFIX}/bin"}
SYS_LIB_DIR=${SYS_LIB_DIR:-"${SYS_PREFIX}/lib"}
#use wasmception
if [ $# -eq 0 ] || [ "$1" = "wasmception" ]; then
echo "Setting up for wasmception"
WASM_PREFIX=${WASM_PREFIX:-"${SYS_SRC_PREFIX}/${SILVERFISH}/wasmception"}
WASM_BIN=${WASM_BIN:-"${WASM_PREFIX}/dist/bin"}
WASM_SYSROOT=${WASM_SYSROOT:-"${WASM_PREFIX}/sysroot"}
WASM_TARGET=${WASM_TARGET:-"wasm32-unknown-unknown-wasm"}
WASM_BIN_PREFIX=${WASM_BIN_PREFIX:-"$WASM_TARGET"}
WASM_TOOLS=ar
elif [ "$1" = "wasi" ]; then
echo "Setting up for wasi-sdk"
#use wasi-sdk
WASM_PREFIX=${WASM_PREFIX:-${WASM_SDK:-"/opt/wasi-sdk"}}
WASM_BIN=${WASM_BIN:-"${WASM_PREFIX}/bin"}
WASM_SYSROOT=${WASM_SYSROOT:-"${WASM_PREFIX}/share/sysroot"}
WASM_TARGET=${WASM_TARGET:-"wasm32-wasi"}
WASM_BIN_PREFIX=${WASM_BIN_PREFIX:-"$WASM_TARGET"}
WASM_TOOLS=ar dwarfdump nm ranlib size
fi
# silverfish compiler binary!
BINS=${SILVERFISH}
DEVSRC=${SYS_BIN_DIR}/'devenv_src.sh'
rm -f ${SYS_BIN_DIR}/*
install -d -v "$SYS_BIN_DIR" || exit 1
for bin in $BINS; do
ln -sfv "${SYS_SF_REL_DIR}/${bin}" "${SYS_BIN_DIR}/${bin}"
done
for file in clang clang++; do
wrapper_file="$(mktemp)"
cat >"$wrapper_file" <<EOT
#! /bin/sh
exec "${WASM_BIN}/${file}" --target="$WASM_TARGET" --sysroot="$WASM_SYSROOT" "\$@"
EOT
install -p -v "$wrapper_file" "${SYS_BIN_DIR}/${WASM_BIN_PREFIX}-${file}"
rm -f "$wrapper_file"
done
#for file in ar dwarfdump nm ranlib size; do
for file in ${WASM_TOOLS}; do
ln -sfv "${WASM_BIN}/llvm-${file}" "${SYS_BIN_DIR}/${WASM_BIN_PREFIX}-${file}"
done
for file in ld; do
ln -sfv "${WASM_BIN}/wasm-${file}" "${SYS_BIN_DIR}/${WASM_BIN_PREFIX}-${file}"
done
ln -svf "${SYS_BIN_DIR}/${WASM_BIN_PREFIX}-clang" "${SYS_BIN_DIR}/${WASM_BIN_PREFIX}-gcc"
ln -svf "${SYS_BIN_DIR}/${WASM_BIN_PREFIX}-clang++" "${SYS_BIN_DIR}/${WASM_BIN_PREFIX}-g++"
echo "Done!"

@ -0,0 +1,55 @@
CC=clang
RTDIR=src/
CFILES=${RTDIR}/*.c ${RTDIR}/libc/*.c ${RTDIR}/memory/common.c
RUNTIME=bin/awsmrt
INC=include/
OPTFLAGS = -O3
OPTFLAGS += -flto -g
LDFLAGS = -Wl,--export-dynamic -ldl -lm
USE_MEM = USE_MEM_VM
CFLAGS = ${OPTFLAGS} -D${USE_MEM} -I${INC} -pthread
CFLAGS += -DX86_64
CFLAGS += -DDEBUG
CFLAGS += -D_GNU_SOURCE
#CFLAGS += -DNOSTDIO
CFLAGS += -DUSE_UVIO
#CFLAGS += -DUSE_SYSCALL
#CFLAGS += -DPREEMPT_DISABLE
MAKE= make --no-print-directory
JSMN=jsmn
JSMNINC=-I${JSMN}
JSMNCFLAGS=${JSMNINC} -DJSMN_STATIC -DJSMN_STRICT
ifeq ($(USE_MEM),USE_MEM_GENERIC)
CFILES += ${RTDIR}/memory/generic.c
else ifeq ($(USE_MEM),USE_MEM_VM)
CFILES += ${RTDIR}/memory/64bit_nix.c
endif
all: clean runtime tools
runtime:
@echo "Compiling runtime"
@mkdir -p bin/
@${CC} ${CFLAGS} ${LDFLAGS} ${CFILES} ${JSMNCFLAGS} -L/usr/lib/ -luv $^ -o ${RUNTIME}
tools:
# @echo "Compiling tools"
@${MAKE} -C tools
clean:
@echo "Cleaning up runtime"
@rm -f ${RUNTIME}
# @echo "Cleaning up tools"
@${MAKE} -C tools clean
fetch:
@git submodule update --init --recursive
init: fetch clean runtime tools
.PHONY: all init clean fetch libuv runtime tools

@ -0,0 +1,199 @@
/* code from https://github.com/gwsystems/silverfish/blob/master/runtime/runtime.c */
#include <assert.h>
#include <types.h>
// TODO: Throughout here we use `assert` for error conditions, which isn't optimal
// Instead we should use `unlikely` branches to a single trapping function (which should optimize better)
// The below functions are for implementing WASM instructions
// ROTL and ROTR helper functions
INLINE u32
rotl_u32(u32 n, u32 c_u32)
{
// WASM requires a modulus here (usually a single bitwise op, but it means we need no assert)
unsigned int c = c_u32 % (CHAR_BIT * sizeof(n));
const unsigned int mask = (CHAR_BIT * sizeof(n) - 1); // assumes width is a power of 2.
c &= mask;
return (n << c) | (n >> ((-c) & mask));
}
INLINE u32
rotr_u32(u32 n, u32 c_u32)
{
// WASM requires a modulus here (usually a single bitwise op, but it means we need no assert)
unsigned int c = c_u32 % (CHAR_BIT * sizeof(n));
const unsigned int mask = (CHAR_BIT * sizeof(n) - 1);
c &= mask;
return (n>>c) | (n << ((-c) & mask));
}
INLINE u64
rotl_u64(u64 n, u64 c_u64)
{
// WASM requires a modulus here (usually a single bitwise op, but it means we need no assert)
unsigned int c = c_u64 % (CHAR_BIT * sizeof(n));
const unsigned int mask = (CHAR_BIT * sizeof(n) - 1); // assumes width is a power of 2.
c &= mask;
return (n << c) | (n >> ((-c) & mask));
}
INLINE u64
rotr_u64(u64 n, u64 c_u64)
{
// WASM requires a modulus here (usually a single bitwise op, but it means we need no assert)
unsigned int c = c_u64 % (CHAR_BIT * sizeof(n));
const unsigned int mask = (CHAR_BIT * sizeof(n) - 1);
c &= mask;
return (n >> c) | (n << ((-c) & mask));
}
// Now safe division and remainder
INLINE u32
u32_div(u32 a, u32 b)
{
assert(b);
return a / b;
}
INLINE u32
u32_rem(u32 a, u32 b)
{
assert(b);
return a % b;
}
INLINE i32
i32_div(i32 a, i32 b)
{
assert(b && (a != INT32_MIN || b != -1));
return a / b;
}
INLINE i32
i32_rem(i32 a, i32 b)
{
assert(b && (a != INT32_MIN || b != -1));
return a % b;
}
INLINE u64
u64_div(u64 a, u64 b)
{
assert(b);
return a / b;
}
INLINE u64
u64_rem(u64 a, u64 b)
{
assert(b);
return a % b;
}
INLINE i64
i64_div(i64 a, i64 b)
{
assert(b && (a != INT64_MIN || b != -1));
return a / b;
}
INLINE i64
i64_rem(i64 a, i64 b)
{
assert(b && (a != INT64_MIN || b != -1));
return a % b;
}
// float to integer conversion methods
// In C, float => int conversions always truncate
// If a int2float(int::min_value) <= float <= int2float(int::max_value), it must always be safe to truncate it
u32
u32_trunc_f32(float f)
{
assert(0 <= f && f <= UINT32_MAX);
return (u32) f;
}
i32
i32_trunc_f32(float f)
{
assert(INT32_MIN <= f && f <= INT32_MAX );
return (i32) f;
}
u32
u32_trunc_f64(double f)
{
assert(0 <= f && f <= UINT32_MAX);
return (u32) f;
}
i32
i32_trunc_f64(double f)
{
assert(INT32_MIN <= f && f <= INT32_MAX );
return (i32) f;
}
u64
u64_trunc_f32(float f)
{
assert(0 <= f && f <= UINT64_MAX);
return (u64) f;
}
i64
i64_trunc_f32(float f)
{
assert(INT64_MIN <= f && f <= INT64_MAX);
return (i64) f;
}
u64
u64_trunc_f64(double f)
{
assert(0 <= f && f <= UINT64_MAX);
return (u64) f;
}
i64
i64_trunc_f64(double f)
{
assert(INT64_MIN <= f && f <= INT64_MAX);
return (i64) f;
}
// Float => Float truncation functions
INLINE float
f32_trunc_f32(float f)
{
return trunc(f);
}
INLINE float
f32_min(float a, float b)
{
return a < b ? a : b;
}
INLINE float
f32_max(float a, float b)
{
return a > b ? a : b;
}
INLINE double
f64_min(double a, double b)
{
return a < b ? a : b;
}
INLINE double
f64_max(double a, double b)
{
return a > b ? a : b;
}

@ -0,0 +1,130 @@
/* https://github.com/gwsystems/silverfish/blob/master/runtime/memory/64bit_nix.c */
#include <types.h>
#ifdef USE_MEM_VM
// All of these are pretty generic
INLINE float
get_f32(i32 offset)
{
char *mem_as_chars = (char *)sandbox_lmbase;
void *address = &mem_as_chars[offset];
return *(float *)address;
}
INLINE double
get_f64(i32 offset)
{
char *mem_as_chars = (char *)sandbox_lmbase;
void *address = &mem_as_chars[offset];
return *(double *)address;
}
INLINE i8
get_i8(i32 offset)
{
char *mem_as_chars = (char *)sandbox_lmbase;
void *address = &mem_as_chars[offset];
return *(i8 *)address;
}
INLINE i16
get_i16(i32 offset)
{
char *mem_as_chars = (char *)sandbox_lmbase;
void *address = &mem_as_chars[offset];
return *(i16 *)address;
}
INLINE i32
get_i32(i32 offset)
{
char *mem_as_chars = (char *)sandbox_lmbase;
void *address = &mem_as_chars[offset];
return *(i32 *)address;
}
INLINE i64
get_i64(i32 offset)
{
char *mem_as_chars = (char *)sandbox_lmbase;
void *address = &mem_as_chars[offset];
return *(i64 *)address;
}
// Now setting routines
INLINE void
set_f32(i32 offset, float v)
{
char *mem_as_chars = (char *)sandbox_lmbase;
void *address = &mem_as_chars[offset];
*(float *)address = v;
}
INLINE void
set_f64(i32 offset, double v)
{
char *mem_as_chars = (char *)sandbox_lmbase;
void *address = &mem_as_chars[offset];
*(double *)address = v;
}
INLINE void
set_i8(i32 offset, i8 v)
{
char *mem_as_chars = (char *)sandbox_lmbase;
void *address = &mem_as_chars[offset];
*(i8 *)address = v;
}
INLINE void
set_i16(i32 offset, i16 v)
{
char *mem_as_chars = (char *)sandbox_lmbase;
void *address = &mem_as_chars[offset];
*(i16 *)address = v;
}
INLINE void
set_i32(i32 offset, i32 v)
{
char *mem_as_chars = (char *)sandbox_lmbase;
void *address = &mem_as_chars[offset];
*(i32 *)address = v;
}
INLINE void
set_i64(i32 offset, i64 v)
{
char *mem_as_chars = (char *)sandbox_lmbase;
void *address = &mem_as_chars[offset];
*(i64 *)address = v;
}
// Table handling functionality
INLINE char *
get_function_from_table(u32 idx, u32 type_id)
{
assert(idx < INDIRECT_TABLE_SIZE);
struct indirect_table_entry f = module_indirect_table[idx];
assert(f.type_id == type_id && f.func_pointer);
return f.func_pointer;
}
#else
#error "Incorrect memory module!"
#endif

@ -0,0 +1,37 @@
#ifndef ARCH_AARCH64_CONTEXT_H
#define ARCH_AARCH64_CONTEXT_H
#include <unistd.h>
#include <ucontext.h>
typedef uint64_t reg_t;
#define ARCH_NREGS 31 // TODO: aarch64 context-switch assembly and registers!
/*
* This is the slowpath switch to a preempted sandbox!
* SIGUSR1 on the current thread and restore mcontext there!
*/
extern void __attribute__((noreturn)) sandbox_switch_preempt(void);
struct arch_context {
reg_t regs[ARCH_NREGS];
mcontext_t mctx;
};
typedef struct arch_context arch_context_t;
extern __thread arch_context_t base_context;
static inline void
arch_context_init(arch_context_t *actx, reg_t ip, reg_t sp)
{
memset(&actx->mctx, 0, sizeof(mcontext_t));
memset((void *)actx->regs, 0, sizeof(reg_t) * ARCH_NREGS);
}
static inline int
arch_context_switch(arch_context_t *ca, arch_context_t *na)
{
return 0;
}
#endif /* ARCH_AARCH64_CONTEXT_H */

@ -0,0 +1,14 @@
#ifndef ARCH_CONTEXT_H
#define ARCH_CONTEXT_H
#if defined(AARCH64)
#include "aarch64/context.h"
#elif defined(X86_64)
#include "x86_64/context.h"
#else
#warning "Architecture not set. Using x86_64"
#define X86_64
#include "x86_64/context.h"
#endif
#endif /* ARCH_CONTEXT_H */

@ -0,0 +1,155 @@
#ifndef ARCH_X86_64_CONTEXT_H
#define ARCH_X86_64_CONTEXT_H
#include <assert.h>
#include <unistd.h>
#include <ucontext.h>
/*
* Register strict ordering>
* rax = (regs + 0) = 0(%%reg)
* rbx = (regs + 1) = 8(%%reg)
* rcx = (regs + 2) = 16(%%reg)
* rdx = (regs + 3) = 24(%%reg)
* rbp = (regs + 4) = 32(%%reg)
* rsp = (regs + 5) = 40(%%reg)
* rsi = (regs + 6) = 48(%%reg)
* rdi = (regs + 7) = 56(%%reg)
* r8 = (regs + 8) = 64(%%reg)
* r9 = (regs + 9) = 72(%%reg)
* r10 = (regs + 10) = 80(%%reg)
* r11 = (regs + 11) = 88(%%reg)
* r12 = (regs + 12) = 96(%%reg)
* r13 = (regs + 13) = 104(%%reg)
* r14 = (regs + 14) = 112(%%reg)
* r15 = (regs + 15) = 120(%%reg)
* rip = (regs + 16) = 128(%%reg)
*/
typedef uint64_t reg_t;
#define ARCH_NREGS (16 /* GP registers */ + 1 /* for IP */)
/*
* This is the slowpath switch to a preempted sandbox!
* SIGUSR1 on the current thread and restore mcontext there!
*/
extern void __attribute__((noreturn)) sandbox_switch_preempt(void);
struct arch_context {
reg_t regs[ARCH_NREGS];
mcontext_t mctx;
};
typedef struct arch_context arch_context_t;
extern __thread arch_context_t base_context;
static void
arch_mcontext_save(arch_context_t *ctx, mcontext_t *mc)
{
assert(ctx != &base_context);
ctx->regs[5] = 0;
memset(ctx->regs, 0, ARCH_NREGS * sizeof(reg_t));
memcpy(&ctx->mctx, mc, sizeof(mcontext_t));
}
static void
arch_mcontext_restore(mcontext_t *mc, arch_context_t *ctx)
{
assert(ctx != &base_context);
// if ctx->regs[5] is set, this was last in a user-level context switch state!
// else restore mcontext..
if (ctx->regs[5]) {
mc->gregs[REG_RSP] = ctx->regs[5];
mc->gregs[REG_RIP] = ctx->regs[16];
ctx->regs[5] = 0;
} else {
memcpy(mc, &ctx->mctx, sizeof(mcontext_t));
memset(&ctx->mctx, 0, sizeof(mcontext_t));
}
}
static void __attribute__((noinline))
arch_context_init(arch_context_t *actx, reg_t ip, reg_t sp)
{
memset(&actx->mctx, 0, sizeof(mcontext_t));
memset((void *)actx->regs, 0, sizeof(reg_t) * ARCH_NREGS);
if (sp) {
/*
* context_switch conventions: bp is expected to be on top of the stack
* when co-op context switching..
*
* so push sp on this new stack and use
* that new sp as sp for switching to sandbox!
*/
asm volatile (
"movq %%rsp, %%rbx\n\t" \
"movq %%rax, %%rsp\n\t" \
"pushq %%rax\n\t" \
"movq %%rsp, %%rax\n\t" \
"movq %%rbx, %%rsp\n\t" \
: "=a" (sp)
: "a" (sp)
: "memory", "cc", "rbx"
);
}
*(actx->regs + 5) = sp;
*(actx->regs + 16) = ip;
}
static inline int
arch_context_switch(arch_context_t *ca, arch_context_t *na)
{
if (!ca) {
assert(na);
// switching from "no sandbox to execute" state to "executing a sandbox"
ca = &base_context;
} else if (!na) {
assert(ca);
// switching from "executing a sandbox" to "no execution" state.
na = &base_context;
} else {
assert(na && ca);
// switching between sandboxes.
}
reg_t *cr = ca->regs, *nr = na->regs;
assert(cr && nr);
/* TODO: slowpath: signal the current pthread if resuming a preempted sandbox! */
asm volatile ( \
"pushq %%rbp\n\t" \
"movq %%rsp, %%rbp\n\t" \
"movq $2f, 128(%%rax)\n\t" \
"movq %%rsp, 40(%%rax)\n\t" \
"cmpq $0, 40(%%rbx)\n\t" \
"je 1f\n\t" \
"movq 40(%%rbx), %%rsp\n\t" \
"jmpq *128(%%rbx)\n\t" \
"1:\n\t" \
"call sandbox_switch_preempt\n\t" \
".align 8\n\t" \
"2:\n\t" \
"movq $0, 40(%%rbx)\n\t" \
".align 8\n\t" \
"3:\n\t" \
"popq %%rbp\n\t" \
:
: "a" (cr), "b" (nr)
: "memory", "cc", "rcx", "rdx", "rsi", "rdi",
"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
"xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7",
"xmm8", "xmm9", "xmm10","xmm11","xmm12","xmm13","xmm14","xmm15"
);
return 0;
}
#endif /* ARCH_X86_64_CONTEXT_H */

@ -0,0 +1,91 @@
#ifndef SFRT_MODULE_H
#define SFRT_MODULE_H
#include <uv.h>
#include "types.h"
struct module {
char name[MOD_NAME_MAX]; //not sure if i care for now.
char path[MOD_PATH_MAX]; //to dlopen if it has not been opened already.
void *dl_handle;
mod_main_fn_t entry_fn;
mod_glb_fn_t glb_init_fn;
mod_mem_fn_t mem_init_fn;
mod_tbl_fn_t tbl_init_fn;
i32 nargs; //as per the specification somewhere.
/* i32 nrets; */
u32 stack_size; // a specification?
u64 max_memory; //perhaps a specification of the module.
u32 timeout; //again part of the module specification.
u32 refcnt; //ref count how many instances exist here.
u32 udpport;
uv_udp_t udpsrv; // udp server to listen to requests.
struct sockaddr_in srvaddr;
// FIXME: for now, per-sandbox. no reason to have it be per-sandbox.
struct indirect_table_entry indirect_table[INDIRECT_TABLE_SIZE];
// TODO: what else?
};
// a runtime resource, perhaps use "malloc" on this?
struct module *module_alloc(char *mod_name, char *mod_path, u32 udp_port, i32 nargs, i32 nrets, u32 stack_sz, u32 max_heap, u32 timeout/*, ...*/);
// frees only if refcnt == 0
void module_free(struct module *mod);
struct module *module_find(char *name);
static inline int
module_is_valid(struct module *mod)
{
if (mod && mod->dl_handle && mod->entry_fn) return 1;
return 0;
}
static inline void
module_table_init(struct module *mod)
{
// called in a sandbox.
mod->tbl_init_fn();
}
static inline void
module_memory_init(struct module *mod)
{
// called in a sandbox.
mod->mem_init_fn();
}
static inline i32
module_entry(struct module *mod, i32 argc, i32 argv)
{
return mod->entry_fn(argc, argv);
}
// instantiate this module.
static inline void
module_acquire(struct module *mod)
{
// FIXME: atomic.
mod->refcnt++;
}
static inline void
module_release(struct module *mod)
{
// FIXME: atomic.
mod->refcnt--;
}
static inline i32
module_nargs(struct module *mod)
{
return mod->nargs;
}
#endif /* SFRT_MODULE_H */

@ -0,0 +1,189 @@
/***
* Copyright 2009-2017 by Gabriel Parmer. All rights reserved.
* Redistribution of this file is permitted under the BSD 2 clause license.
* Author: Gabriel Parmer, gparmer@gwu.edu, 2017
*
* History:
* - Initial implementation, ~2009
* - Adapted for parsec and relicensed, 2016
*/
/*
* API Conventions:
* - obj, new, and tmp are pointers of type T where T is the struct containing the linked list
* - head is a pointer to struct ps_list_head
* - l is the list field name within T
* - type is T without any ()
* - all ps_list_head_* functions should be applied to struct ps_list_head pointers
* - all ps_list_* functions should be passed items of type T, not struct ps_list_head
* - as with most macro-based APIs, please avoid passing in functions that cannot be multiply evaluated;
* generally passing only variables is a good move
*
* Example Usage:
*
* struct ps_list_head h;
* struct foo {
* struct ps_list l;
* void *d;
* } node, *i, *tmp;
*
* ps_list_head_init(&h);
* ps_list_init(&node);
* ps_list_head_add(&h, &node, l);
* ...
* for (i = ps_list_head_first(&h, struct foo, l) ;
* i != ps_list_head(&h, struct foo, l) ;
* i = ps_list_next(i, l)) { ... }
*
* for (ps_list_iter_init(&h, i, l) ; !ps_list_iter_term(&h, i, l) ; i = ps_list_next(i, l)) { ... }
*
* ps_list_foreach(&h, i, l) { ... }
*
* ps_list_foreach_del(&h, i, tmp, l) {
* ps_list_rem(i, l);
* ps_free(i);
* }
*
*/
#ifndef PS_LIST_H
#define PS_LIST_H
struct ps_list {
struct ps_list *n, *p;
};
/*
* This is a separate type to 1) provide guidance on how to use the
* API, and 2) to prevent developers from comparing pointers that
* should not be compared.
*/
struct ps_list_head {
struct ps_list l;
};
#define PS_LIST_DEF_NAME list
static inline void
ps_list_ll_init(struct ps_list *l)
{ l->n = l->p = l; }
static inline void
ps_list_head_init(struct ps_list_head *lh)
{ ps_list_ll_init(&lh->l); }
static inline int
ps_list_ll_empty(struct ps_list *l)
{ return l->n == l; }
static inline int
ps_list_head_empty(struct ps_list_head *lh)
{ return ps_list_ll_empty(&lh->l); }
static inline void
ps_list_ll_add(struct ps_list *l, struct ps_list *new)
{
new->n = l->n;
new->p = l;
l->n = new;
new->n->p = new;
}
static inline void
ps_list_ll_rem(struct ps_list *l)
{
l->n->p = l->p;
l->p->n = l->n;
l->p = l->n = l;
}
#define ps_offsetof(s, field) __builtin_offsetof(s, field)
//#define ps_offsetof(s, field) ((unsigned long)&(((s *)0)->field))
#define ps_container(intern, type, field) \
((type *)((char *)(intern) - ps_offsetof(type, field)))
/*
* Get a pointer to the object containing *l, of a type shared with
* *o. Importantly, "o" is not accessed here, and is _only_ used for
* its type. It will typically be the iterator/cursor working through
* a list. Do _not_ use this function. It is a utility used by the
* following functions.
*/
#define ps_list_obj_get(l, o, lname) \
ps_container(l, __typeof__(*(o)), lname)
//(typeof (*(o)) *)(((char*)(l)) - ps_offsetof(typeof(*(o)), lname))
/***
* The object API. These functions are called with pointers to your
* own (typed) structures.
*/
#define ps_list_is_head(lh, o, lname) (ps_list_obj_get((lh), (o), lname) == (o))
/* functions for if we don't use the default name for the list field */
#define ps_list_singleton(o, lname) ps_list_ll_empty(&(o)->lname)
#define ps_list_init(o, lname) ps_list_ll_init(&(o)->lname)
#define ps_list_next(o, lname) ps_list_obj_get((o)->lname.n, (o), lname)
#define ps_list_prev(o, lname) ps_list_obj_get((o)->lname.p, (o), lname)
#define ps_list_add(o, n, lname) ps_list_ll_add(&(o)->lname, &(n)->lname)
#define ps_list_append(o, n, lname) ps_list_add(ps_list_prev((o), lname), n, lname)
#define ps_list_rem(o, lname) ps_list_ll_rem(&(o)->lname)
#define ps_list_head_add(lh, o, lname) ps_list_ll_add((&(lh)->l), &(o)->lname)
#define ps_list_head_append(lh, o, lname) ps_list_ll_add(((&(lh)->l)->p), &(o)->lname)
/**
* Explicit type API: Pass in the types of the nodes in the list, and
* the name of the ps_list field in that type.
*/
#define ps_list_head_first(lh, type, lname) \
ps_container(((lh)->l.n), type, lname)
#define ps_list_head_last(lh, type, lname) \
ps_container(((lh)->l.p), type, lname)
/* If your struct named the list field "list" (as defined by PS_LIST_DEF_NAME */
#define ps_list_is_head_d(lh, o) ps_list_is_head(lh, o, PS_LIST_DEF_NAME)
#define ps_list_singleton_d(o) ps_list_singleton(o, PS_LIST_DEF_NAME)
#define ps_list_init_d(o) ps_list_init(o, PS_LIST_DEF_NAME)
#define ps_list_next_d(o) ps_list_next(o, PS_LIST_DEF_NAME)
#define ps_list_prev_d(o) ps_list_prev(o, PS_LIST_DEF_NAME)
#define ps_list_add_d(o, n) ps_list_add(o, n, PS_LIST_DEF_NAME)
#define ps_list_append_d(o, n) ps_list_append(o, n, PS_LIST_DEF_NAME)
#define ps_list_rem_d(o) ps_list_rem(o, PS_LIST_DEF_NAME)
#define ps_list_head_last_d(lh, o) ps_list_head_last(lh, o, PS_LIST_DEF_NAME)
#define ps_list_head_first_d(lh, type) ps_list_head_first(lh, type, PS_LIST_DEF_NAME)
#define ps_list_head_add_d(lh, o) ps_list_head_add(lh, o, PS_LIST_DEF_NAME)
#define ps_list_head_append_d(lh, o) ps_list_head_append(lh, o, PS_LIST_DEF_NAME)
/**
* Iteration API
*/
/* Iteration without mutating the list */
#define ps_list_foreach(head, iter, lname) \
for (iter = ps_list_head_first((head), __typeof__(*iter), lname) ; \
!ps_list_is_head((head), iter, lname) ; \
(iter) = ps_list_next(iter, lname))
#define ps_list_foreach_d(head, iter) ps_list_foreach(head, iter, PS_LIST_DEF_NAME)
/*
* Iteration where the current node can be ps_list_rem'ed.
* Notes:
* - typeof(iter) == typeof(tmp)
* - ps_list_add can be used on iter, but the added node will not be iterated over
*
* TODO: Add SMR/parallel version of this macro
*/
#define ps_list_foreach_del(head, iter, tmp, lname) \
for (iter = ps_list_head_first((head), __typeof__(*iter), lname), \
(tmp) = ps_list_next((iter), lname) ; \
!ps_list_is_head((head), iter, lname) ; \
(iter) = (tmp), (tmp) = ps_list_next((tmp), lname))
#define ps_list_foreach_del_d(head, iter, tmp) ps_list_foreach_del(head, iter, tmp, PS_LIST_DEF_NAME)
#endif /* PS_LIST_H */

@ -0,0 +1,55 @@
#ifndef SFRT_RUNTIME_H
#define SFRT_RUNTIME_H
#include "types.h"
#include <uv.h>
#include "sandbox.h"
void alloc_linear_memory(void);
void expand_memory(void);
void free_linear_memory(void *base, u32 bound, u32 max);
// Assumption: bounds_check < WASM_PAGE_SIZE
INLINE char *get_memory_ptr_for_runtime(u32 offset, u32 bounds_check);
static inline void *
get_memory_ptr_void(u32 offset, u32 bounds_check)
{
return (void*) get_memory_ptr_for_runtime(offset, bounds_check);
}
static inline char *
get_memory_string(u32 offset)
{
char *naive_ptr = get_memory_ptr_for_runtime(offset, 1);
int i = 0;
while (1) {
// Keep bounds checking the waters over and over until we know it's safe (we find a terminating character)
char ith_element = get_memory_ptr_for_runtime(offset, i + 1)[i];
if (ith_element == '\0') return naive_ptr;
i++;
}
}
INLINE char *get_function_from_table(u32 idx, u32 type_id);
// libc/* might need to do some setup for the libc setup
void stub_init(char *modulename, i32 offset, mod_init_libc_fn_t fn);
void runtime_init(void);
static inline void
runtime_on_alloc(uv_handle_t *h, size_t suggested, uv_buf_t *buf)
{
buf->base = malloc(suggested);
memset(buf->base, 0, suggested);
buf->len = suggested;
}
extern __thread uv_loop_t uvio;
static inline uv_loop_t *
runtime_uvio(void)
{ return &uvio; }
#endif /* SFRT_RUNTIME_H */

@ -0,0 +1,211 @@
#ifndef SFRT_SANDBOX_H
#define SFRT_SANDBOX_H
#include "ps_list.h"
#include "module.h"
#include "arch/context.h"
#include "softint.h"
#include <ucontext.h>
#include <uv.h>
struct io_handle {
int fd;
struct stat s_cache;
union uv_any_handle uvh;
};
typedef enum {
SANDBOX_FREE,
SANDBOX_RUNNABLE,
SANDBOX_BLOCKED,
SANDBOX_WOKEN, //for race in block()/wakeup()
SANDBOX_RETURNED, //waiting for parent to read status?
} sandbox_state_t;
/*
* This is the slowpath switch to a preempted sandbox!
* SIGUSR1 on the current thread and restore mcontext there!
*/
extern void __attribute__((noreturn)) sandbox_switch_preempt(void);
struct sandbox {
sandbox_state_t state;
void *linear_start;
u32 linear_size;
u32 linear_max_size;
void *stack_start; // guess we need a mechanism for stack allocation.
u32 stack_size; // and to set the size of it.
arch_context_t ctxt; //register context for context switch.
// TODO: are all these necessary?
u64 actual_deadline;
u64 expected_deadline;
u64 total_time;
u64 remaining_time;
u64 start_time;
struct module *mod; //which module is this an instance of?
//struct indirect_table_entry indirect_table[INDIRECT_TABLE_SIZE];
i32 args_offset; //actual placement of args in the sandbox.
/* i32 ret_offset; //placement of return value(s) in the sandbox. */
void *args; // args from request, must be of module->nargs size.
i32 retval;
struct io_handle handles[SBOX_MAX_OPEN];
char *read_buf;
ssize_t read_len, read_size;
struct ps_list list;
// track I/O handles?
};
// a runtime resource, malloc on this!
struct sandbox *sandbox_alloc(struct module *mod, char *args);
// should free stack and heap resources.. also any I/O handles.
void sandbox_free(struct sandbox *sbox);
// next_sandbox only used in SIGUSR1
extern __thread struct sandbox *current_sandbox;
extern __thread arch_context_t *next_context;
typedef struct sandbox sandbox_t;
static inline struct sandbox *
sandbox_current(void)
{ return current_sandbox; }
static inline void
sandbox_current_set(struct sandbox *sbox)
{
int dis = 0;
if (softint_enabled()) {
dis = 1;
softint_disable();
}
// FIXME: critical-section.
current_sandbox = sbox;
if (sbox == NULL) return;
sandbox_lmbase = sbox->linear_start;
sandbox_lmbound = sbox->linear_size;
// TODO: module table or sandbox table?
module_indirect_table = sbox->mod->indirect_table;
if (dis) softint_enable();
}
static inline struct module *
sandbox_module(struct sandbox *s)
{
if (!s) return NULL;
return s->mod;
}
static inline void
sandbox_switch(struct sandbox *next)
{
arch_context_t *n = next == NULL ? NULL : &next->ctxt;
// disable interrupts (signals)
softint_disable();
// switch sandbox (register context & base/bound/table)
struct sandbox *curr = sandbox_current();
arch_context_t *c = curr == NULL ? NULL : &curr->ctxt;
sandbox_current_set(next);
// save current's registers and restore next's registers.
next_context = n;
arch_context_switch(c, n);
next_context = NULL;
// enable interrupts (signals)
softint_enable();
}
static inline char *
sandbox_args(void)
{
struct sandbox *c = sandbox_current();
return (char *)c->args;
}
void sandbox_run(struct sandbox *s);
void *sandbox_run_func(void *data);
struct sandbox *sandbox_schedule(void);
void sandbox_block(void);
void sandbox_wakeup(sandbox_t *sb);
// should be the entry-point for each sandbox so it can do per-sandbox mem/etc init.
// should have been called with stack allocated and sandbox_current() set!
void sandbox_entry(void);
void sandbox_exit(void);
static inline int
io_handle_preopen(void)
{
struct sandbox *s = sandbox_current();
int i;
for (i = 0; i < SBOX_MAX_OPEN; i++) {
if (s->handles[i].fd < 0) break;
}
if (i == SBOX_MAX_OPEN) return -1;
s->handles[i].fd = SBOX_PREOPEN_MAGIC;
memset(&s->handles[i].uvh, 0, sizeof(union uv_any_handle));
return i;
}
static inline int
io_handle_open(int fd)
{
struct sandbox *s = sandbox_current();
if (fd < 0) return fd;
int i = io_handle_preopen();
s->handles[i].fd = fd; //well, per sandbox.. so synchronization necessary!
return i;
}
static inline int
io_handle_preopen_set(int idx, int fd)
{
struct sandbox *s = sandbox_current();
if (idx >= SBOX_MAX_OPEN || idx < 0) return -1;
if (fd < 0 || s->handles[idx].fd != SBOX_PREOPEN_MAGIC) return -1;
s->handles[idx].fd = fd;
return idx;
}
static inline int
io_handle_fd(int idx)
{
struct sandbox *s = sandbox_current();
if (idx >= SBOX_MAX_OPEN || idx < 0) return -1;
return s->handles[idx].fd;
}
static inline void
io_handle_close(int idx)
{
struct sandbox *s = sandbox_current();
if (idx >= SBOX_MAX_OPEN || idx < 0) return;
s->handles[idx].fd = -1;
}
static inline union uv_any_handle *
io_handle_uv_get(int idx)
{
struct sandbox *s = sandbox_current();
if (idx >= SBOX_MAX_OPEN || idx < 0) return NULL;
return &s->handles[idx].uvh;
}
#endif /* SFRT_SANDBOX_H */

@ -0,0 +1,73 @@
#ifndef SFRT_SOFTINT_H
#define SFRT_SOFTINT_H
#include <stdbool.h>
#include <assert.h>
#include <signal.h>
static inline int
softint_mask(int sig)
{
sigset_t set;
int ret;
assert(sig == SIGALRM || sig == SIGUSR1);
/* all threads created by the calling thread will have sig blocked */
sigemptyset(&set);
sigaddset(&set, sig);
ret = pthread_sigmask(SIG_BLOCK, &set, NULL);
if (ret != 0) {
errno = ret;
perror("pthread_sigmask");
exit(-1);
}
return 0;
}
static inline int
softint_unmask(int sig)
{
sigset_t set;
int ret;
assert(sig == SIGALRM || sig == SIGUSR1);
/* all threads created by the calling thread will have sig unblocked */
sigemptyset(&set);
sigaddset(&set, sig);
ret = pthread_sigmask(SIG_UNBLOCK, &set, NULL);
if (ret != 0) {
errno = ret;
perror("pthread_sigmask");
exit(-1);
}
return 0;
}
extern __thread volatile sig_atomic_t softint_off;
static inline void
softint_disable(void)
{
while (__sync_bool_compare_and_swap(&softint_off, 0, 1) == false) ;
}
static inline void
softint_enable(void)
{
if (__sync_bool_compare_and_swap(&softint_off, 1, 0) == false) assert(0);
}
static inline int
softint_enabled(void)
{
return (softint_off == 0);
}
void softint_init(void);
void softint_timer_arm(void);
void softint_timer_disarm(void);
#endif /* SFRT_SOFTINT_H */

@ -0,0 +1,129 @@
#ifndef SFRT_TYPES_H
#define SFRT_TYPES_H
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <math.h>
#include <printf.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/uio.h>
#define EXPORT __attribute__ ((visibility ("default")))
#define IMPORT __attribute__ ((visibility ("default")))
#define INLINE __attribute__((always_inline))
#define WEAK __attribute__((weak))
// Type alias's so I don't have to write uint32_t a million times
typedef signed char i8;
typedef unsigned char u8;
typedef int16_t i16;
typedef uint16_t u16;
typedef int32_t i32;
typedef uint32_t u32;
typedef int64_t i64;
typedef uint64_t u64;
// FIXME: per-module configuration?
#define WASM_PAGE_SIZE (1024 * 64) //64KB
#define WASM_START_PAGES (1<<8) //16MB
#define WASM_MAX_PAGES (1<<15) //4GB
#define WASM_STACK_SIZE (1<<15) // FIXME: fixed size for now.
// These are per module symbols and I'd need to dlsym for each module. instead just use global constants, see above macros.
// The code generator compiles in the starting number of wasm pages, and the maximum number of pages
// If we try and allocate more than max_pages, we should fault
//extern u32 starting_pages;
//extern u32 max_pages;
// The code generator also compiles in stubs that populate the linear memory and function table
void populate_memory(void);
void populate_table(void);
// memory/* also provides the table access functions
// TODO: Change this to use a compiled in size
#define INDIRECT_TABLE_SIZE 1024
struct indirect_table_entry {
u32 type_id;
void *func_pointer;
};
extern __thread struct indirect_table_entry *module_indirect_table;
// for sandbox linear memory isolation
extern __thread void *sandbox_lmbase;
extern __thread u32 sandbox_lmbound;
extern i32 logfd;
// functions in the module to lookup and call per sandbox.
typedef i32 (*mod_main_fn_t)(i32 a, i32 b);
typedef void (*mod_glb_fn_t)(void);
typedef void (*mod_mem_fn_t)(void);
typedef void (*mod_tbl_fn_t)(void);
typedef void (*mod_init_libc_fn_t)(i32, i32);
typedef enum {
MOD_ARG_MODPATH = 0,
MOD_ARG_MODPORT,
MOD_ARG_MODNAME,
MOD_ARG_MODNARGS,
MOD_ARG_MAX,
} mod_argindex_t;
#define MOD_MAIN_FN "wasmf_main"
#define MOD_GLB_FN "populate_globals"
#define MOD_MEM_FN "populate_memory"
#define MOD_TBL_FN "populate_table"
#define MOD_INIT_LIBC_FN "wasmf___init_libc"
#define MOD_MAX_ARGS 16
#define MOD_ARG_MAX_SZ 64
#define MOD_MAX 1024
#define MOD_NAME_MAX 32
#define MOD_PATH_MAX 256
#define JSON_ELE_MAX 16
// FIXME: some naive work-stealing here..
#define SBOX_PULL_MAX 16
#define SBOX_MAX_OPEN 32
#define SBOX_PREOPEN_MAGIC (707707707) // reads lol lol lol upside down
#define SOFTINT_TIMER_START_USEC (10*1000) //start timers 10 us from now.
#define SOFTINT_TIMER_PERIOD_USEC (1000*100) // 100ms timer..
#ifdef DEBUG
#ifdef NOSTDIO
#define debuglog(fmt,...) dprintf(logfd, "(%d,%lu) %s: " fmt, sched_getcpu(), pthread_self(), __func__, ## __VA_ARGS__)
#else
#define debuglog(fmt,...) printf("(%d,%lu) %s: " fmt, sched_getcpu(), pthread_self(), __func__, ## __VA_ARGS__)
#endif
#else
#define debuglog(fmt,...)
#endif
#define GLB_STDOUT "/dev/null"
#define GLB_STDERR "/dev/null"
#define GLB_STDIN "/dev/zero"
#define LOGFILE "awesome.log"
#define RDWR_VEC_MAX 16
#define MOD_REQ_CORE 0 // core dedicated to check module requests..
#define SBOX_NCORES 2 // number of sandboxing threads/cores..
#endif /* SFRT_TYPES_H */

@ -0,0 +1,13 @@
#ifndef SFRT_UTIL_H
#define SFRT_UTIL_H
#include <sandbox.h>
#include <module.h>
/* perhaps move it to module.h or sandbox.h? */
struct sandbox *util_parse_sandbox_string_custom(struct module *m, char *str);
struct sandbox *util_parse_sandbox_string_json(struct module *m, char *str);
int util_parse_modules_file_json(char *filename);
int util_parse_modules_file_custom(char *filename);
#endif /* SFRT_UTIL_H */

@ -0,0 +1 @@
Subproject commit 85695f3d5903b1cd5b4030efe50db3b4f5f3c928

@ -0,0 +1,193 @@
/* https://github.com/gwsystems/silverfish/blob/master/runtime/libc/libc_backing.c */
#include <runtime.h>
extern i32 inner_syscall_handler(i32 n, i32 a, i32 b, i32 c, i32 d, i32 e, i32 f);
i32
env_syscall_handler(i32 n, i32 a, i32 b, i32 c, i32 d, i32 e, i32 f)
{
i32 i = inner_syscall_handler(n, a, b, c, d, e, f);
return i;
}
i32
env___syscall(i32 n, i32 a, i32 b, i32 c, i32 d, i32 e, i32 f)
{
return env_syscall_handler(n, a, b, c, d, e, f);
}
// Atomic functions, with definitions stolen from musl
i32
env_a_ctz_64(u64 x)
{
__asm__( "bsf %1,%0" : "=r"(x) : "r"(x) );
return x;
}
//static inline int a_ctz_l(unsigned long x)
//{
// __asm__( "bsf %1,%0" : "=r"(x) : "r"(x) );
// return x;
//}
INLINE void
env_a_and_64(i32 p_off, u64 v)
{
uint64_t* p = get_memory_ptr_void(p_off, sizeof(uint64_t));
*p &= v;
// __asm__( "lock ; and %1, %0"
// : "=m"(*p) : "r"(v) : "memory" );
}
INLINE void
env_a_or_64(i32 p_off, i64 v)
{
assert(sizeof(i64) == sizeof(uint64_t));
uint64_t* p = get_memory_ptr_void(p_off, sizeof(i64));
*p |= v;
// __asm__( "lock ; or %1, %0"
// : "=m"(*p) : "r"(v) : "memory" );
}
//static inline void a_or_l(volatile void *p, long v)
//{
// __asm__( "lock ; or %1, %0"
// : "=m"(*(long *)p) : "r"(v) : "memory" );
//}
//
//static inline void *a_cas_p(volatile void *p, void *t, void *s)
//{
// __asm__( "lock ; cmpxchg %3, %1"
// : "=a"(t), "=m"(*(long *)p) : "a"(t), "r"(s) : "memory" );
// return t;
//}
//
i32
env_a_cas(i32 p_off, i32 t, i32 s)
{
assert(sizeof(i32) == sizeof(volatile int));
volatile int* p = get_memory_ptr_void(p_off, sizeof(i32));
__asm__( "lock ; cmpxchg %3, %1"
: "=a"(t), "=m"(*p) : "a"(t), "r"(s) : "memory" );
return t;
}
void
env_a_or(i32 p_off, i32 v)
{
assert(sizeof(i32) == sizeof(volatile int));
volatile int* p = get_memory_ptr_void(p_off, sizeof(i32));
__asm__( "lock ; or %1, %0"
: "=m"(*p) : "r"(v) : "memory" );
}
//static inline void a_and(volatile int *p, int v)
//{
// __asm__( "lock ; and %1, %0"
// : "=m"(*p) : "r"(v) : "memory" );
//}
i32
env_a_swap(i32 x_off, i32 v)
{
assert(sizeof(i32) == sizeof(volatile int));
volatile int* x = get_memory_ptr_void(x_off, sizeof(i32));
__asm__( "xchg %0, %1" : "=r"(v), "=m"(*x) : "0"(v) : "memory" );
return v;
}
i32
env_a_fetch_add(i32 x_off, i32 v)
{
assert(sizeof(i32) == sizeof(volatile int));
volatile int* x = get_memory_ptr_void(x_off, sizeof(i32));
__asm__( "lock ; xadd %0, %1" : "=r"(v), "=m"(*x) : "0"(v) : "memory" );
return v;
}
void
env_a_inc(i32 x_off)
{
assert(sizeof(i32) == sizeof(volatile int));
volatile int* x = get_memory_ptr_void(x_off, sizeof(i32));
__asm__( "lock ; incl %0" : "=m"(*x) : "m"(*x) : "memory" );
}
void
env_a_dec(i32 x_off)
{
assert(sizeof(i32) == sizeof(volatile int));
volatile int* x = get_memory_ptr_void(x_off, sizeof(i32));
__asm__( "lock ; decl %0" : "=m"(*x) : "m"(*x) : "memory" );
}
void
env_a_store(i32 p_off, i32 x)
{
assert(sizeof(i32) == sizeof(volatile int));
volatile int* p = get_memory_ptr_void(p_off, sizeof(i32));
__asm__ __volatile__(
"mov %1, %0 ; lock ; orl $0,(%%esp)" : "=m"(*p) : "r"(x) : "memory" );
}
void
env_do_spin(i32 i)
{
__asm__ __volatile__( "pause" : : : "memory" );
}
void
env_do_crash(i32 i)
{
printf("crashing: %d\n", i);
assert(0);
}
int
env_a_ctz_32(i32 x)
{
__asm__( "bsf %1,%0" : "=r"(x) : "r"(x) );
return x;
}
void
env_do_barrier(i32 x)
{
__asm__ __volatile__( "" : : : "memory" );
}
void
env___unmapself(u32 base, u32 size)
{
// Just do some no op
}
// Floating point routines
// TODO: Do a fair comparison between musl and wasm-musl
INLINE double
env_sin(double d)
{
return sin(d);
}
INLINE double
env_cos(double d)
{
return cos(d);
}

@ -0,0 +1,666 @@
#ifdef USE_SYSCALL
/* code from https://github.com/gwsystems/silverfish/blob/master/runtime/libc/libc_backing.c */
#include <runtime.h>
#include <sys/types.h>
#include <sys/socket.h>
// What should we tell the child program its UID and GID are?
#define UID 0xFF
#define GID 0xFE
// Elf auxilary vector values (see google for what those are)
#define AT_NULL 0
#define AT_IGNORE 1
#define AT_EXECFD 2
#define AT_PHDR 3
#define AT_PHENT 4
#define AT_PHNUM 5
#define AT_PAGESZ 6
#define AT_BASE 7
#define AT_FLAGS 8
#define AT_ENTRY 9
#define AT_NOTELF 10
#define AT_UID 11
#define AT_EUID 12
#define AT_GID 13
#define AT_EGID 14
#define AT_CLKTCK 17
#define AT_SECURE 23
#define AT_BASE_PLATFORM 24
#define AT_RANDOM 25
// offset = a WASM ptr to memory the runtime can use
void
stub_init(char *program_name, i32 offset, mod_init_libc_fn_t libcfn)
{
printf("Don't think we should reinit libc! so ignore for now!\n");
}
// Emulated syscall implementations
// We define our own syscall numbers, because WASM uses x86_64 values even on systems that are not x86_64
#define SYS_READ 0
u32
wasm_read(i32 filedes, i32 buf_offset, i32 nbyte)
{
char* buf = get_memory_ptr_void(buf_offset, nbyte);
i32 res = (i32) read(filedes, buf, nbyte);
if (res == -1) return -errno;
return res;
}
#define SYS_WRITE 1
i32
wasm_write(i32 fd, i32 buf_offset, i32 buf_size)
{
char* buf = get_memory_ptr_void(buf_offset, buf_size);
i32 res = (i32) write(fd, buf, buf_size);
if (res == -1) return -errno;
return res;
}
#define WO_RDONLY 00
#define WO_WRONLY 01
#define WO_RDWR 02
#define WO_CREAT 0100
#define WO_EXCL 0200
#define WO_NOCTTY 0400
#define WO_TRUNC 01000
#define WO_APPEND 02000
#define WO_NONBLOCK 04000
#define WO_DSYNC 010000
#define WO_SYNC 04010000
#define WO_RSYNC 04010000
#define WO_DIRECTORY 0200000
#define WO_NOFOLLOW 0400000
#define WO_CLOEXEC 02000000
#define SYS_OPEN 2
i32
wasm_open(i32 path_off, i32 flags, i32 mode)
{
char* path = get_memory_string(path_off);
i32 modified_flags = 0;
if (flags & WO_RDONLY) {
modified_flags |= O_RDONLY;
flags ^= WO_RDONLY;
}
if (flags & WO_WRONLY) {
modified_flags |= O_WRONLY;
flags ^= WO_WRONLY;
}
if (flags & WO_RDWR) {
modified_flags |= O_RDWR;
flags ^= WO_RDWR;
}
if (flags & WO_APPEND) {
modified_flags |= O_APPEND;
flags ^= WO_APPEND;
}
if (flags & WO_CREAT) {
modified_flags |= O_CREAT;
flags ^= WO_CREAT;
}
if (flags & WO_EXCL) {
modified_flags |= O_EXCL;
flags ^= WO_EXCL;
}
i32 res = (i32) open(path, modified_flags, mode);
if (res == -1) return -errno;
return res;
}
#define SYS_CLOSE 3
i32
wasm_close(i32 fd)
{
i32 res = (i32) close(fd);
if (res == -1) return -errno;
return res;
}
// What the wasm stat structure looks like
struct wasm_stat {
i64 st_dev;
u64 st_ino;
u32 st_nlink;
u32 st_mode;
u32 st_uid;
u32 st_gid;
u32 __pad0;
u64 st_rdev;
u64 st_size;
i32 st_blksize;
i64 st_blocks;
struct { i32 tv_sec; i32 tv_nsec; } st_atim;
struct { i32 tv_sec; i32 tv_nsec; } st_mtim;
struct { i32 tv_sec; i32 tv_nsec; } st_ctim;
i32 __pad1[3];
};
#define SYS_STAT 4
// What the OSX stat structure looks like:
// struct stat { /* when _DARWIN_FEATURE_64_BIT_INODE is NOT defined */
// dev_t st_dev; /* device inode resides on */
// ino_t st_ino; /* inode's number */
// mode_t st_mode; /* inode protection mode */
// nlink_t st_nlink; /* number of hard links to the file */
// uid_t st_uid; /* user-id of owner */
// gid_t st_gid; /* group-id of owner */
// dev_t st_rdev; /* device type, for special file inode */
// struct timespec st_atimespec; /* time of last access */
// struct timespec st_mtimespec; /* time of last data modification */
// struct timespec st_ctimespec; /* time of last file status change */
// off_t st_size; /* file size, in bytes */
// quad_t st_blocks; /* blocks allocated for file */
// u_long st_blksize;/* optimal file sys I/O ops blocksize */
// u_long st_flags; /* user defined flags for file */
// u_long st_gen; /* file generation number */
// };
i32
wasm_stat(u32 path_str_offset, i32 stat_offset)
{
char *path = get_memory_string(path_str_offset);
struct wasm_stat* stat_ptr = get_memory_ptr_void(stat_offset, sizeof(struct wasm_stat));
struct stat stat;
i32 res = lstat(path, &stat);
if (res == -1) return -errno;
*stat_ptr = (struct wasm_stat) {
.st_dev = stat.st_dev,
.st_ino = stat.st_ino,
.st_nlink = stat.st_nlink,
.st_mode = stat.st_mode,
.st_uid = stat.st_uid,
.st_gid = stat.st_gid,
.st_rdev = stat.st_rdev,
.st_size = stat.st_size,
.st_blksize = stat.st_blksize,
.st_blocks = stat.st_blocks,
};
#ifdef __APPLE__
stat_ptr->st_atim.tv_sec = stat.st_atimespec.tv_sec;
stat_ptr->st_atim.tv_nsec = stat.st_atimespec.tv_nsec;
stat_ptr->st_mtim.tv_sec = stat.st_mtimespec.tv_sec;
stat_ptr->st_mtim.tv_nsec = stat.st_mtimespec.tv_nsec;
stat_ptr->st_ctim.tv_sec = stat.st_ctimespec.tv_sec;
stat_ptr->st_ctim.tv_nsec = stat.st_ctimespec.tv_nsec;
#else
stat_ptr->st_atim.tv_sec = stat.st_atim.tv_sec;
stat_ptr->st_atim.tv_nsec = stat.st_atim.tv_nsec;
stat_ptr->st_mtim.tv_sec = stat.st_mtim.tv_sec;
stat_ptr->st_mtim.tv_nsec = stat.st_mtim.tv_nsec;
stat_ptr->st_ctim.tv_sec = stat.st_ctim.tv_sec;
stat_ptr->st_ctim.tv_nsec = stat.st_ctim.tv_nsec;
#endif
return res;
}
#define SYS_FSTAT 5
i32
wasm_fstat(i32 filedes, i32 stat_offset)
{
struct wasm_stat* stat_ptr = get_memory_ptr_void(stat_offset, sizeof(struct wasm_stat));
struct stat stat;
i32 res = fstat(filedes, &stat);
if (res == -1) return -errno;
*stat_ptr = (struct wasm_stat) {
.st_dev = stat.st_dev,
.st_ino = stat.st_ino,
.st_nlink = stat.st_nlink,
.st_mode = stat.st_mode,
.st_uid = stat.st_uid,
.st_gid = stat.st_gid,
.st_rdev = stat.st_rdev,
.st_size = stat.st_size,
.st_blksize = stat.st_blksize,
.st_blocks = stat.st_blocks,
};
#ifdef __APPLE__
stat_ptr->st_atim.tv_sec = stat.st_atimespec.tv_sec;
stat_ptr->st_atim.tv_nsec = stat.st_atimespec.tv_nsec;
stat_ptr->st_mtim.tv_sec = stat.st_mtimespec.tv_sec;
stat_ptr->st_mtim.tv_nsec = stat.st_mtimespec.tv_nsec;
stat_ptr->st_ctim.tv_sec = stat.st_ctimespec.tv_sec;
stat_ptr->st_ctim.tv_nsec = stat.st_ctimespec.tv_nsec;
#else
stat_ptr->st_atim.tv_sec = stat.st_atim.tv_sec;
stat_ptr->st_atim.tv_nsec = stat.st_atim.tv_nsec;
stat_ptr->st_mtim.tv_sec = stat.st_mtim.tv_sec;
stat_ptr->st_mtim.tv_nsec = stat.st_mtim.tv_nsec;
stat_ptr->st_ctim.tv_sec = stat.st_ctim.tv_sec;
stat_ptr->st_ctim.tv_nsec = stat.st_ctim.tv_nsec;
#endif
return res;
}
#define SYS_LSTAT 6
i32
wasm_lstat(i32 path_str_offset, i32 stat_offset)
{
char *path = get_memory_string(path_str_offset);
struct wasm_stat* stat_ptr = get_memory_ptr_void(stat_offset, sizeof(struct wasm_stat));
struct stat stat;
i32 res = lstat(path, &stat);
if (res == -1) return -errno;
*stat_ptr = (struct wasm_stat) {
.st_dev = stat.st_dev,
.st_ino = stat.st_ino,
.st_nlink = stat.st_nlink,
.st_mode = stat.st_mode,
.st_uid = stat.st_uid,
.st_gid = stat.st_gid,
.st_rdev = stat.st_rdev,
.st_size = stat.st_size,
.st_blksize = stat.st_blksize,
.st_blocks = stat.st_blocks,
};
#ifdef __APPLE__
stat_ptr->st_atim.tv_sec = stat.st_atimespec.tv_sec;
stat_ptr->st_atim.tv_nsec = stat.st_atimespec.tv_nsec;
stat_ptr->st_mtim.tv_sec = stat.st_mtimespec.tv_sec;
stat_ptr->st_mtim.tv_nsec = stat.st_mtimespec.tv_nsec;
stat_ptr->st_ctim.tv_sec = stat.st_ctimespec.tv_sec;
stat_ptr->st_ctim.tv_nsec = stat.st_ctimespec.tv_nsec;
#else
stat_ptr->st_atim.tv_sec = stat.st_atim.tv_sec;
stat_ptr->st_atim.tv_nsec = stat.st_atim.tv_nsec;
stat_ptr->st_mtim.tv_sec = stat.st_mtim.tv_sec;
stat_ptr->st_mtim.tv_nsec = stat.st_mtim.tv_nsec;
stat_ptr->st_ctim.tv_sec = stat.st_ctim.tv_sec;
stat_ptr->st_ctim.tv_nsec = stat.st_ctim.tv_nsec;
#endif
return res;
}
#define SYS_LSEEK 8
i32
wasm_lseek(i32 filedes, i32 file_offset, i32 whence)
{
i32 res = (i32) lseek(filedes, file_offset, whence);
if (res == -1) return -errno;
return res;
}
#define SYS_MMAP 9
u32
wasm_mmap(i32 addr, i32 len, i32 prot, i32 flags, i32 fd, i32 offset)
{
if (addr != 0) {
printf("parameter void *addr is not supported!\n");
assert(0);
}
if (fd != -1) {
printf("file mapping is not supported!\n");
assert(0);
}
assert(len % WASM_PAGE_SIZE == 0);
i32 result = sandbox_lmbound;
for (int i = 0; i < len / WASM_PAGE_SIZE; i++) {
expand_memory();
}
return result;
}
#define SYS_MUNMAP 11
#define SYS_BRK 12
#define SYS_RT_SIGACTION 13
#define SYS_RT_SIGPROGMASK 14
#define SYS_IOCTL 16
i32
wasm_ioctl(i32 fd, i32 request, i32 data_offet)
{
// musl libc does some ioctls to stdout, so just allow these to silently go through
// FIXME: The above is idiotic
return 0;
}
#define SYS_READV 19
struct wasm_iovec {
i32 base_offset;
i32 len;
};
i32
wasm_readv(i32 fd, i32 iov_offset, i32 iovcnt)
{
i32 read = 0;
struct wasm_iovec *iov = get_memory_ptr_void(iov_offset, iovcnt * sizeof(struct wasm_iovec));
for (int i = 0; i < iovcnt; i++) {
read += wasm_read(fd, iov[i].base_offset, iov[i].len);
}
return read;
}
#define SYS_WRITEV 20
i32
wasm_writev(i32 fd, i32 iov_offset, i32 iovcnt)
{
struct wasm_iovec *iov = get_memory_ptr_void(iov_offset, iovcnt * sizeof(struct wasm_iovec));
// If we aren't on MUSL, pass writev to printf if possible
#if defined(__APPLE__) || defined(__GLIBC__)
if (fd == 1) {
int sum = 0;
for (int i = 0; i < iovcnt; i++) {
i32 len = iov[i].len;
void* ptr = get_memory_ptr_void(iov[i].base_offset, len);
printf("%.*s", len, ptr);
sum += len;
}
return sum;
}
#endif
struct iovec vecs[iovcnt];
for (int i = 0; i < iovcnt; i++) {
i32 len = iov[i].len;
void* ptr = get_memory_ptr_void(iov[i].base_offset, len);
vecs[i] = (struct iovec) {ptr, len};
}
i32 res = (i32) writev(fd, vecs, iovcnt);
if (res == -1) return -errno;
return res;
}
#define SYS_MADVISE 28
#define SYS_GETPID 39
u32
wasm_getpid()
{
return (u32) getpid();
}
#define WF_DUPFD 0
#define WF_GETFD 1
#define WF_SETFD 2
#define WF_GETFL 3
#define WF_SETFL 4
#define WF_SETOWN 8
#define WF_GETOWN 9
#define WF_SETSIG 10
#define WF_GETSIG 11
#define WF_GETLK 5
#define WF_SETLK 6
#define WF_SETLKW 7
#define SYS_FCNTL 72
u32
wasm_fcntl(u32 fd, u32 cmd, u32 arg_or_lock_ptr)
{
switch (cmd) {
case WF_SETFD:
// return fcntl(fd, F_SETFD, arg_or_lock_ptr);
return 0;
case WF_SETLK:
return 0;
default:
assert(0);
}
}
#define SYS_FSYNC 74
u32
wasm_fsync(u32 filedes)
{
u32 res = fsync(filedes);
if (res == -1) return -errno;
return 0;
}
#define SYS_GETCWD 79
u32
wasm_getcwd(u32 buf_offset, u32 buf_size)
{
char* buf = get_memory_ptr_void(buf_offset, buf_size);
char* res = getcwd(buf, buf_size);
if (!res) return 0;
return buf_offset;
}
#define SYS_UNLINK 87
u32
wasm_unlink(u32 path_str_offset)
{
char* str = get_memory_string(path_str_offset);
u32 res = unlink(str);
if (res == -1) return -errno;
return 0;
}
#define SYS_GETEUID 107
u32
wasm_geteuid()
{
return (u32) geteuid();
}
#define SYS_SET_THREAD_AREA 205
#define SYS_SET_TID_ADDRESS 218
#define SYS_GET_TIME 228
struct wasm_time_spec {
u32 sec;
u32 nanosec;
};
i32
wasm_get_time(i32 clock_id, i32 timespec_off)
{
clockid_t real_clock;
switch (clock_id) {
case 0:
real_clock = CLOCK_REALTIME;
break;
case 1:
real_clock = CLOCK_MONOTONIC;
break;
case 2:
real_clock = CLOCK_PROCESS_CPUTIME_ID;
break;
default:
assert(0);
}
struct wasm_time_spec* timespec = get_memory_ptr_void(timespec_off, sizeof(struct wasm_time_spec));
struct timespec native_timespec = { 0, 0 };
int res = clock_gettime(real_clock, &native_timespec);
if (res == -1) return -errno;
timespec->sec = native_timespec.tv_sec;
timespec->nanosec = native_timespec.tv_nsec;
return res;
}
#define SYS_EXIT_GROUP 231
i32
wasm_exit_group(i32 status)
{
exit(status);
return 0;
}
#define SYS_FCHOWN 93
i32
wasm_fchown(i32 fd, u32 owner, u32 group)
{
return fchown(fd, owner, group);
}
// networking syscalls
#define SYS_SOCKET 41
#define SYS_CONNECT 42
#define SYS_ACCEPT 43
#define SYS_BIND 49
#define SYS_LISTEN 50
i32
wasm_socket(i32 domain, i32 type, i32 protocol)
{
return socket(domain, type, protocol);
}
i32
wasm_connect(i32 sockfd, i32 sockaddr_offset, i32 addrlen)
{
return connect(sockfd, get_memory_ptr_void(sockaddr_offset, addrlen), addrlen);
}
i32
wasm_accept(i32 sockfd, i32 sockaddr_offset, i32 addrlen_offset)
{
socklen_t *addrlen = get_memory_ptr_void(addrlen_offset, sizeof(socklen_t));
return accept(sockfd, get_memory_ptr_void(sockaddr_offset, *addrlen), addrlen);
}
i32
wasm_bind(i32 sockfd, i32 sockaddr_offset, i32 addrlen)
{
return bind(sockfd, get_memory_ptr_void(sockaddr_offset, addrlen), addrlen);
}
i32
wasm_listen(i32 sockfd, i32 backlog)
{
return listen(sockfd, backlog);
}
#define SYS_SENDTO 44
#define SYS_RECVFROM 45
i32
wasm_sendto(i32 fd, i32 buff_offset, i32 len, i32 flags, i32 sockaddr_offset, i32 sockaddr_len)
{
char *buf = get_memory_ptr_void(buff_offset, len);
struct sockaddr *addr = sockaddr_len ? get_memory_ptr_void(sockaddr_offset, sockaddr_len) : NULL;
return sendto(fd, buf, len, flags, addr, sockaddr_len);
}
i32
wasm_recvfrom(i32 fd, i32 buff_offset, i32 size, i32 flags, i32 sockaddr_offset, i32 socklen_offset)
{
char *buf = get_memory_ptr_void(buff_offset, size);
socklen_t *len = get_memory_ptr_void(socklen_offset, sizeof(socklen_t));
struct sockaddr *addr = *len ? get_memory_ptr_void(sockaddr_offset, *len) : NULL;
return recvfrom(fd, buf, size, flags, addr, addr ? len : NULL);
}
i32
inner_syscall_handler(i32 n, i32 a, i32 b, i32 c, i32 d, i32 e, i32 f)
{
i32 res;
switch(n) {
case SYS_READ: return wasm_read(a, b, c);
case SYS_WRITE: return wasm_write(a, b, c);
case SYS_OPEN: return wasm_open(a, b, c);
case SYS_CLOSE: return wasm_close(a);
case SYS_STAT: return wasm_stat(a, b);
case SYS_FSTAT: return wasm_fstat(a, b);
case SYS_LSTAT: return wasm_lstat(a, b);
case SYS_LSEEK: return wasm_lseek(a, b, c);
case SYS_MMAP: return wasm_mmap(a, b, c, d, e, f);
case SYS_MUNMAP: return 0;
case SYS_BRK: return 0;
case SYS_RT_SIGACTION: return 0;
case SYS_RT_SIGPROGMASK: return 0;
case SYS_IOCTL: return wasm_ioctl(a, b, c);
case SYS_READV: return wasm_readv(a, b, c);
case SYS_WRITEV: return wasm_writev(a, b, c);
case SYS_MADVISE: return 0;
case SYS_GETPID: return wasm_getpid();
case SYS_FCNTL: return wasm_fcntl(a, b, c);
case SYS_FSYNC: return wasm_fsync(a);
case SYS_UNLINK: return wasm_unlink(a);
case SYS_GETCWD: return wasm_getcwd(a, b);
case SYS_GETEUID: return wasm_geteuid();
case SYS_SET_THREAD_AREA: return 0;
case SYS_SET_TID_ADDRESS: return 0;
case SYS_GET_TIME: return wasm_get_time(a, b);
case SYS_EXIT_GROUP: return wasm_exit_group(a);
case SYS_FCHOWN: return wasm_fchown(a, b, c);
case SYS_SOCKET: return wasm_socket(a, b, c);
case SYS_CONNECT: return wasm_connect(a, b, c);
case SYS_ACCEPT: return wasm_accept(a, b, c);
case SYS_BIND: return wasm_bind(a, b, c);
case SYS_LISTEN: return wasm_listen(a, b);
case SYS_SENDTO: return wasm_sendto(a, b, c, d, e, f);
case SYS_RECVFROM: return wasm_recvfrom(a, b, c, d, e, f);
}
printf("syscall %d (%d, %d, %d, %d, %d, %d)\n", n, a, b, c, d, e, f);
assert(0);
return 0;
}
#endif

File diff suppressed because it is too large Load Diff

@ -0,0 +1,100 @@
#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>
#include <dlfcn.h>
#include <pthread.h>
#include <sched.h>
#include <unistd.h>
#include <runtime.h>
#include <sandbox.h>
#include <softint.h>
#include <util.h>
#define MOD_LINE_MAX 1024
i32 logfd = -1;
u32 ncores = 0, sbox_ncores = 0, sbox_core_st = 0;
static void
usage(char *cmd)
{
printf("%s <modules_file>\n", cmd);
debuglog("%s <modules_file>\n", cmd);
}
int
main(int argc, char* argv[])
{
int i = 0, rtthd_ret[SBOX_NCORES] = { 0 };
pthread_t rtthd[SBOX_NCORES];
if (argc != 2) {
usage(argv[0]);
exit(-1);
}
ncores = sysconf(_SC_NPROCESSORS_ONLN);
if (ncores > 1) {
u32 x = ncores - 1;
sbox_ncores = SBOX_NCORES;
if (x < SBOX_NCORES) sbox_ncores = x;
sbox_core_st = 1;
} else {
sbox_ncores = 1;
}
debuglog("Number of cores %u, sandboxing cores %u (start: %u) and module reqs %u\n", ncores, sbox_ncores, sbox_core_st, MOD_REQ_CORE);
#ifdef NOSTDIO
fclose(stdout);
fclose(stderr);
fclose(stdin);
logfd = open(LOGFILE, O_CREAT | O_TRUNC | O_WRONLY, S_IRWXU | S_IRWXG);
if (logfd < 0) {
perror("open");
exit(-1);
}
#else
logfd = 1;
#endif
runtime_init();
debuglog("Parsing modules file [%s]\n", argv[1]);
if (util_parse_modules_file_json(argv[1])) {
// if (util_parse_modules_file_custom(argv[1])) {
printf("failed to parse modules file[%s]\n", argv[1]);
exit(-1);
}
for (i = 0; i < sbox_ncores; i++) {
int ret = pthread_create(&rtthd[i], NULL, sandbox_run_func, (void *)&rtthd_ret[i]);
if (ret) {
errno = ret;
perror("pthread_create");
exit(-1);
}
cpu_set_t cs;
CPU_ZERO(&cs);
CPU_SET(sbox_core_st + i, &cs);
ret = pthread_setaffinity_np(rtthd[i], sizeof(cs), &cs);
assert(ret == 0);
}
debuglog("Sandboxing environment ready!\n");
for (i = 0; i < sbox_ncores; i++) {
int ret = pthread_join(rtthd[i], NULL);
if (ret) {
errno = ret;
perror("pthread_join");
exit(-1);
}
}
// runtime threads run forever!! so join should not return!!
printf("\nOh no..!! This can't be happening..!!\n");
exit(-1);
}

@ -0,0 +1,86 @@
/* Code from https://github.com/gwsystems/silverfish/blob/master/runtime/memory/64bit_nix.c */
#include <runtime.h>
#include <sandbox.h>
#ifdef USE_MEM_VM
#include <sys/mman.h>
#define MAX_LINEAR_MEM ((1LL << 32) + WASM_PAGE_SIZE)
void
alloc_linear_memory(void)
{
struct sandbox *curr = sandbox_current();
// Map 4gb + PAGE_SIZE of memory that will fault when accessed
// We allocate the extra page so that reads off the end will also fail
sandbox_lmbase = mmap(NULL, MAX_LINEAR_MEM, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (sandbox_lmbase == MAP_FAILED) {
perror("Mapping of initial unusable region failed");
exit(1);
}
void *map_result = mmap(sandbox_lmbase, WASM_PAGE_SIZE * WASM_START_PAGES, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
if (map_result == MAP_FAILED) {
perror("Mapping of initial memory failed");
exit(1);
}
sandbox_lmbound = WASM_PAGE_SIZE * WASM_START_PAGES;
curr->linear_start = sandbox_lmbase;
curr->linear_size = sandbox_lmbound;
}
void
free_linear_memory(void *base, u32 bound, u32 max)
{
struct sandbox *curr = sandbox_current();
assert(base && bound);
// cannot free currently executing sandbox's memory
assert(base != curr->linear_start || base != sandbox_lmbase);
int ret = munmap(base, MAX_LINEAR_MEM);
if (ret) perror("munmap");
}
void
expand_memory(void)
{
struct sandbox *curr = sandbox_current();
// max_pages = 0 => no limit: FIXME
assert(sandbox_lmbound / WASM_PAGE_SIZE < WASM_MAX_PAGES);
// Remap the relevant wasm page to readable
char *mem_as_chars = sandbox_lmbase;
char *page_address = &mem_as_chars[sandbox_lmbound];
void *map_result = mmap(page_address, WASM_PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
if (map_result == MAP_FAILED) {
perror("Mapping of new memory failed");
exit(1);
}
// TODO: check curr->linear_max_size
sandbox_lmbound += WASM_PAGE_SIZE;
curr->linear_size = sandbox_lmbound;
}
INLINE char *
get_memory_ptr_for_runtime(u32 offset, u32 bounds_check)
{
// Due to how we setup memory for x86, the virtual memory mechanism will catch the error, if bounds < WASM_PAGE_SIZE
assert(bounds_check < WASM_PAGE_SIZE ||
(sandbox_lmbound > bounds_check &&
offset <= sandbox_lmbound - bounds_check));
char *mem_as_chars = (char *)sandbox_lmbase;
char *address = &mem_as_chars[offset];
return address;
}
#else
#error "Incorrect runtime memory module!"
#endif

@ -0,0 +1,35 @@
#include <runtime.h>
__thread struct indirect_table_entry *module_indirect_table = NULL;
__thread void *sandbox_lmbase = NULL;
__thread u32 sandbox_lmbound = 0;
// Region initialization helper function
EXPORT void
initialize_region(u32 offset, u32 data_count, char* data)
{
assert(sandbox_lmbound >= data_count);
assert(offset < sandbox_lmbound - data_count);
// FIXME: Hack around segmented and unsegmented access
memcpy(get_memory_ptr_for_runtime(offset, data_count), data, data_count);
}
void
add_function_to_table(u32 idx, u32 type_id, char* pointer)
{
assert(idx < INDIRECT_TABLE_SIZE);
// TODO: atomic for multiple concurrent invocations?
if (module_indirect_table[idx].type_id == type_id && module_indirect_table[idx].func_pointer == pointer) return;
module_indirect_table[idx] = (struct indirect_table_entry) { .type_id = type_id, .func_pointer = pointer };
}
// If we are using runtime globals, we need to populate them
WEAK void
populate_globals()
{
assert(0); // FIXME: is this used in WASM as dynamic modules?
}

@ -0,0 +1,137 @@
#include <runtime.h>
#include <module.h>
#include <stdlib.h>
#include <stdio.h>
#include <dlfcn.h>
#include <uv.h>
#include <util.h>
static struct module *__mod_db[MOD_MAX] = { NULL };
static int __mod_free_off = 0;
// todo: optimize this.. do we care? plus not atomic!!
struct module *
module_find(char *name)
{
int f = __mod_free_off;
for (int i = 0; i < f; i++) {
assert(__mod_db[i]);
if (strcmp(__mod_db[i]->name, name) == 0) return __mod_db[i];
}
return NULL;
}
static inline int
module_add(struct module *m)
{
assert(module_find(m->name) == NULL);
int f = __sync_fetch_and_add(&__mod_free_off, 1);
assert(f < MOD_MAX);
__mod_db[f] = m;
return 0;
}
static void
module_on_recv(uv_udp_t *h, ssize_t nr, const uv_buf_t *rcvbuf, const struct sockaddr *addr, unsigned flags)
{
if (nr <= 0) goto done;
debuglog("MC:%s, %s\n", h->data, rcvbuf->base);
// invoke a function!
struct sandbox *s = util_parse_sandbox_string_json((struct module *)(h->data), rcvbuf->base);
//struct sandbox *s = util_parse_sandbox_string_custom((struct module *)(h->data), rcvbuf->base);
assert(s);
done:
free(rcvbuf->base);
}
static void
module_io_init(struct module *m)
{
int status;
status = uv_udp_init(uv_default_loop(), &m->udpsrv);
assert(status >= 0);
debuglog("MIO:%s,%u\n", m->name, m->udpport);
uv_ip4_addr("127.0.0.1", m->udpport, &m->srvaddr);
status = uv_udp_bind(&m->udpsrv, (const struct sockaddr *)&m->srvaddr, 0);
assert(status >= 0);
m->udpsrv.data = (void *)m;
status = uv_udp_recv_start(&m->udpsrv, runtime_on_alloc, module_on_recv);
assert(status >= 0);
}
struct module *
module_alloc(char *modname, char *modpath, u32 udp_port, i32 nargs, i32 nrets, u32 stacksz, u32 maxheap, u32 timeout)
{
// FIXME: cannot do this at runtime, we may be interfering with a sandbox's heap!
struct module *mod = (struct module *)malloc(sizeof(struct module));
if (!mod) return NULL;
memset(mod, 0, sizeof(struct module));
mod->dl_handle = dlopen(modpath, RTLD_LAZY | RTLD_DEEPBIND);
if (mod->dl_handle == NULL) goto dl_open_error;
mod->entry_fn = (mod_main_fn_t)dlsym(mod->dl_handle, MOD_MAIN_FN);
if (mod->entry_fn == NULL) goto dl_error;
// TODO: don't think this is necessary or implemented.
//mod->glb_init_fn = (mod_glb_fn_t)dlsym(mod->dl_handle, MOD_GLB_FN);
//if (mod->glb_init_fn == NULL) goto dl_error;
mod->mem_init_fn = (mod_mem_fn_t)dlsym(mod->dl_handle, MOD_MEM_FN);
if (mod->mem_init_fn == NULL) goto dl_error;
mod->tbl_init_fn = (mod_tbl_fn_t)dlsym(mod->dl_handle, MOD_TBL_FN);
if (mod->tbl_init_fn == NULL) goto dl_error;
strncpy(mod->name, modname, MOD_NAME_MAX);
strncpy(mod->path, modpath, MOD_PATH_MAX);
mod->nargs = nargs;
/* mod->nrets = nrets; */
mod->stack_size = stacksz == 0 ? WASM_STACK_SIZE : stacksz;
mod->max_memory = maxheap == 0 ? ((u64)WASM_PAGE_SIZE * WASM_MAX_PAGES) : maxheap;
mod->timeout = timeout;
struct indirect_table_entry *cache_tbl = module_indirect_table;
// assumption: modules are created before enabling preemption and before running runtime-sandboxing threads..
// if this isn't a good assumption, just let the first invocation do table init..!!
assert(cache_tbl == NULL);
module_indirect_table = mod->indirect_table;
module_table_init(mod);
module_indirect_table = cache_tbl;
mod->udpport = udp_port;
module_add(mod);
module_io_init(mod);
return mod;
dl_error:
dlclose(mod->dl_handle);
dl_open_error:
free(mod);
debuglog("%s\n", dlerror());
return NULL;
}
void
module_free(struct module *mod)
{
if (mod == NULL) return;
if (mod->dl_handle == NULL) return;
if (mod->refcnt) return;
dlclose(mod->dl_handle);
memset(mod, 0, sizeof(struct module));
// FIXME: use global/static memory. cannot interfere with some sandbox's heap!
free(mod);
}

@ -0,0 +1,237 @@
#include <runtime.h>
#include <types.h>
#include <sandbox.h>
#include <arch/context.h>
#include <module.h>
#include <signal.h>
#include <pthread.h>
#include <sched.h>
#include <softint.h>
#include <uv.h>
// global queue for stealing! TODO: work-stealing-deque
static struct ps_list_head glbq;
static pthread_mutex_t glbq_mtx = PTHREAD_MUTEX_INITIALIZER;
// per-thread (per-core) run and wait queues.. (using doubly-linked-lists)
__thread static struct ps_list_head runq;
__thread static struct ps_list_head waitq;
// current sandbox that is active..
__thread sandbox_t *current_sandbox = NULL;
// context pointer to switch to when this thread gets a SIGUSR1
__thread arch_context_t *next_context = NULL;
// context of the runtime thread before running sandboxes or to resume its "main".
__thread arch_context_t base_context;
// libuv i/o loop handle per sandboxing thread!
__thread uv_loop_t uvio;
static inline void
sandbox_local_run(struct sandbox *s)
{
assert(ps_list_singleton_d(s));
ps_list_head_append_d(&runq, s);
}
static inline int
sandbox_pull(void)
{
int n = 0;
while (n < SBOX_PULL_MAX) {
pthread_mutex_lock(&glbq_mtx);
if (ps_list_head_empty(&glbq)) {
pthread_mutex_unlock(&glbq_mtx);
break;
}
struct sandbox *g = ps_list_head_first_d(&glbq, struct sandbox);
assert(g);
ps_list_rem_d(g);
pthread_mutex_unlock(&glbq_mtx);
debuglog("[%p: %s]\n", g, g->mod->name);
assert(g->state == SANDBOX_RUNNABLE);
sandbox_local_run(g);
n++;
}
return n;
}
static __thread unsigned int in_callback;
void
sandbox_io_nowait(void)
{
#ifdef USE_UVIO
// non-zero if more callbacks are expected
in_callback = 1;
int n = uv_run(runtime_uvio(), UV_RUN_NOWAIT), i = 0;
while (n > 0) {
n--;
uv_run(runtime_uvio(), UV_RUN_NOWAIT);
}
in_callback = 0;
#endif
// zero, so there is nothing (don't block!)
}
struct sandbox *
sandbox_schedule(void)
{
if (!in_callback) sandbox_io_nowait();
struct sandbox *s = NULL;
if (ps_list_head_empty(&runq)) {
if (sandbox_pull() == 0) {
//debuglog("[null: null]\n");
return NULL;
}
}
s = ps_list_head_first_d(&runq, struct sandbox);
// round-robin
ps_list_rem_d(s);
ps_list_head_append_d(&runq, s);
debuglog("[%p: %s]\n", s, s->mod->name);
return s;
}
void
sandbox_wakeup(sandbox_t *s)
{
debuglog("[%p: %s]\n", s, s->mod->name);
// perhaps 2 lists in the sandbox to make sure sandbox is either in runlist or waitlist..
assert(ps_list_singleton_d(s));
s->state = SANDBOX_RUNNABLE;
ps_list_head_append_d(&runq, s);
}
void
sandbox_block(void)
{
// perhaps 2 lists in the sandbox to make sure sandbox is either in runlist or waitlist..
softint_disable();
struct sandbox *c = sandbox_current();
ps_list_rem_d(c);
softint_enable();
debuglog("[%p: %s]\n", c, c->mod->name);
c->state = SANDBOX_BLOCKED;
struct sandbox *s = sandbox_schedule();
sandbox_switch(s);
}
void __attribute__((noinline)) __attribute__((noreturn))
sandbox_switch_preempt(void)
{
pthread_kill(pthread_self(), SIGUSR1);
assert(0); // should not get here..
while (1) ;
}
static inline void
sandbox_local_stop(struct sandbox *s)
{
ps_list_rem_d(s);
}
void *
sandbox_run_func(void *data)
{
arch_context_init(&base_context, 0, 0);
ps_list_head_init(&runq);
ps_list_head_init(&waitq);
softint_off = 0;
next_context = NULL;
#ifndef PREEMPT_DISABLE
softint_unmask(SIGALRM);
softint_unmask(SIGUSR1);
#endif
uv_loop_init(&uvio);
in_callback = 0;
while (1) {
struct sandbox *s = sandbox_schedule();
while (s) {
sandbox_switch(s);
s = sandbox_schedule();
}
}
*(int *)data = -1;
pthread_exit(data);
}
void
sandbox_run(struct sandbox *s)
{
// for now, a pull model...
// sandbox_run adds to the global ready queue..
// each sandboxing thread pulls off of that global ready queue..
debuglog("[%p: %s]\n", s, s->mod->name);
s->state = SANDBOX_RUNNABLE;
pthread_mutex_lock(&glbq_mtx);
ps_list_head_append_d(&glbq, s);
pthread_mutex_unlock(&glbq_mtx);
}
// perhaps respond to request
void
sandbox_exit(void)
{
struct sandbox *curr = sandbox_current();
assert(curr);
debuglog("[%p: %s]\n", curr, curr->mod->name);
sandbox_local_stop(curr);
curr->state = SANDBOX_RETURNED;
// TODO: free resources here? or only from main?
sandbox_switch(sandbox_schedule());
}
void *
runtime_uvio_thdfn(void *d)
{
assert(d == (void *)uv_default_loop());
while (1) {
// runs until there are no events..
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
pthread_yield();
}
assert(0);
return NULL;
}
void
runtime_init(void)
{
ps_list_head_init(&glbq);
softint_mask(SIGUSR1);
softint_mask(SIGALRM);
cpu_set_t cs;
CPU_ZERO(&cs);
CPU_SET(MOD_REQ_CORE, &cs);
pthread_t iothd;
int ret = pthread_create(&iothd, NULL, runtime_uvio_thdfn, (void *)uv_default_loop());
assert(ret == 0);
ret = pthread_setaffinity_np(iothd, sizeof(cpu_set_t), &cs);
assert(ret == 0);
ret = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cs);
assert(ret == 0);
softint_init();
softint_timer_arm();
}

@ -0,0 +1,119 @@
#include <assert.h>
#include <runtime.h>
#include <sandbox.h>
#include <sys/mman.h>
#include <pthread.h>
#include <signal.h>
static inline void
sandbox_args_setup(i32 argc)
{
struct sandbox *curr = sandbox_current();
char *args = sandbox_args();
// whatever gregor has, to be able to pass args to a module!
curr->args_offset = sandbox_lmbound;
assert(sandbox_lmbase == curr->linear_start);
expand_memory();
i32 *array_ptr = get_memory_ptr_void(curr->args_offset, argc * sizeof(i32));
i32 string_off = curr->args_offset + (argc * sizeof(i32));
for (int i = 0; i < argc; i++) {
char *arg = args + (i * MOD_ARG_MAX_SZ);
size_t str_sz = strlen(arg) + 1;
array_ptr[i] = string_off;
// why get_memory_ptr_for_runtime??
strncpy(get_memory_ptr_for_runtime(string_off, strlen(arg) + 1), arg, strlen(arg));
string_off += str_sz;
}
}
void
sandbox_entry(void)
{
struct sandbox *curr = sandbox_current();
// FIXME: is this right? this is the first time this sandbox is running.. so it wont
// return to sandbox_switch() api..
// we'd potentially do what we'd in sandbox_switch() api here for cleanup..
if (!softint_enabled()) {
arch_context_init(&curr->ctxt, 0, 0);
next_context = NULL;
softint_enable();
}
struct module *curr_mod = sandbox_module(curr);
int argc = module_nargs(curr_mod);
// for stdio
int f = io_handle_open(0);
assert(f == 0);
f = io_handle_open(1);
assert(f == 1);
f = io_handle_open(2);
assert(f == 2);
alloc_linear_memory();
// perhaps only initialized for the first instance? or TODO!
//module_table_init(curr_mod);
module_memory_init(curr_mod);
sandbox_args_setup(argc);
curr->retval = module_entry(curr_mod, argc, curr->args_offset);
sandbox_exit();
}
struct sandbox *
sandbox_alloc(struct module *mod, char *args)
{
if (!module_is_valid(mod)) return NULL;
// FIXME: don't use malloc. huge security problem!
// perhaps, main should be in its own sandbox, when it is not running any sandbox.
struct sandbox *sb = (struct sandbox *)malloc(sizeof(struct sandbox));
if (!sb) return NULL;
memset(sb, 0, sizeof(struct sandbox));
//actual module instantiation!
sb->mod = mod;
module_acquire(mod);
sb->args = (void *)args;
sb->stack_size = mod->stack_size;
sb->stack_start = mmap(NULL, sb->stack_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_GROWSDOWN, -1, 0);
if (sb->stack_start == MAP_FAILED) {
perror("mmap");
assert(0);
}
for (int i = 0; i < SBOX_MAX_OPEN; i++) sb->handles[i].fd = -1;
ps_list_init_d(sb);
arch_context_init(&sb->ctxt, (reg_t)sandbox_entry, (reg_t)(sb->stack_start + sb->stack_size));
sandbox_run(sb);
return sb;
}
void
sandbox_free(struct sandbox *sb)
{
// you have to context switch away to free a sandbox.
if (!sb || sb == sandbox_current()) return;
// again sandbox should be done and waiting for the parent.
// TODO: this needs to be enhanced. you may be killing a sandbox when its in any other execution states.
if (sb->state != SANDBOX_RETURNED) return;
module_release(sb->mod);
free(sb->args);
// remove stack! and also heap!
int ret = munmap(sb->stack_start, sb->stack_size);
if (ret) perror("munmap");
// depending on the memory type
free_linear_memory(sb->linear_start, sb->linear_size, sb->linear_max_size);
}

@ -0,0 +1,158 @@
#include <pthread.h>
#include <signal.h>
#include <sys/time.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <ucontext.h>
#include <types.h>
#include <sandbox.h>
#include <module.h>
#include <arch/context.h>
#include <softint.h>
__thread static volatile sig_atomic_t alarm_cnt = 0, usr1_cnt = 0;
__thread volatile sig_atomic_t softint_off = 0;
static const int softints[] = {
SIGALRM,
SIGUSR1
};
void
softint_timer_arm(void)
{
#ifndef PREEMPT_DISABLE
struct itimerval it;
memset(&it, 0, sizeof(struct itimerval));
it.it_value.tv_usec = SOFTINT_TIMER_START_USEC;
it.it_interval.tv_usec = SOFTINT_TIMER_PERIOD_USEC;
int ret = setitimer(ITIMER_REAL, &it, NULL);
if (ret) {
perror("setitimer");
exit(1);
}
#endif
}
void
softint_timer_disarm(void)
{
struct itimerval it;
memset(&it, 0, sizeof(struct itimerval));
it.it_value.tv_sec = 0;
it.it_interval.tv_usec = 0;
int ret = setitimer(ITIMER_REAL, &it, NULL);
if (ret) {
perror("setitimer");
exit(1);
}
}
static inline void
softint_handler(int sig, siginfo_t *si, void *u)
{
#ifdef PREEMPT_DISABLE
assert(0);
#else
struct sandbox *curr = sandbox_current();
ucontext_t *uc = (ucontext_t *)u;
switch(sig) {
case SIGALRM:
{
// if interrupts are disabled.. increment a per_thread counter and return
if (si->si_code == SI_KERNEL) {
// TODO: deliver signal to all other runtime threads..
} else {
assert(si->si_code == SI_TKILL);
}
//debuglog("alrm:%d\n", alarm_cnt);
alarm_cnt++;
// softints per-core..
if (next_context) return;
if (!softint_enabled()) return;
// no sandboxes running..so nothing to preempt..let the "main" scheduler run its course.
if (curr == NULL) return;
// find a next sandbox to run..
struct sandbox *next = sandbox_schedule();
if (next == NULL) return;
if (next == curr) return; // only this sandbox to schedule.. return to it!
// save the current sandbox, state from uc!
arch_mcontext_save(&curr->ctxt, &uc->uc_mcontext);
// sandbox_current_set on it. restore through *uc..
sandbox_current_set(next);
arch_mcontext_restore(&uc->uc_mcontext, &next->ctxt);
// reset if SIGALRM happens before SIGUSR1 and if don't preempt..OR
// perhaps switch here for SIGUSR1 and see if we can clear that signal
// so it doesn't get called on SIGALRM return..
// next_context = NULL;
break;
}
case SIGUSR1:
{
/* we set current before calling pthread_kill! */
assert(next_context && (&curr->ctxt == next_context));
assert(si->si_code == SI_TKILL);
//debuglog("usr1:%d\n", usr1_cnt);
usr1_cnt++;
// sigalrm happened.. such a waste of time..!!
if (next_context == NULL) return;
// make sure sigalrm doesn't mess this up if nested..
assert(!softint_enabled());
// do not save current sandbox.. it is in co-operative switch..
// pick the next from "next_context"..
// assert its "sp" to be zero in regs..
// memcpy from next context..
arch_mcontext_restore(&uc->uc_mcontext, &curr->ctxt);
next_context = NULL;
softint_enable();
break;
}
case SIGPIPE:
case SIGILL:
case SIGFPE:
case SIGSEGV:
{
// determine if the crash was in the sandbox..
// if (pthread_self() == one_of_the_runtime_threads), a sandbox crashed.. kill it.
// another check there could be if it is in linear memory or outside, if outside it could repeat with other sandboxes.. so perhaps restart that thread or start a fresh thread??.
// else, shoot yourself in the head!..
break;
}
default: break;
}
#endif
}
void
softint_init(void)
{
struct sigaction sa;
memset(&sa, 0, sizeof(struct sigaction));
sa.sa_sigaction = softint_handler;
sa.sa_flags = SA_SIGINFO | SA_RESTART;
for (int i = 0; i < (sizeof(softints) / sizeof(softints[0])); i++) {
int ret = sigaction(softints[i], &sa, NULL);
if (ret) {
perror("sigaction");
exit(1);
}
}
}

@ -0,0 +1,305 @@
#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <types.h>
#include <sandbox.h>
#include <module.h>
#include <util.h>
#include <jsmn.h>
#define UTIL_MOD_LINE_MAX 1024
static char *
util_remove_spaces(char *str)
{
int i = 0;
while (isspace(*str)) str++;
i = strlen(str);
while (isspace(str[i-1])) str[i-1]='\0';
return str;
}
int
util_parse_modules_file_json(char *filename)
{
struct stat sb;
memset(&sb, 0, sizeof(struct stat));
if (stat(filename, &sb) < 0) {
perror("stat");
return -1;
}
FILE *mf = fopen(filename, "r");
if (!mf) {
perror("fopen");
return -1;
}
char *filebuf = malloc(sb.st_size);
memset(filebuf, 0, sb.st_size);
int ret = fread(filebuf, sizeof(char), sb.st_size, mf);
debuglog("size read: %d content: %s\n", ret, filebuf);
if (ret != sb.st_size) {
perror("fread");
return -1;
}
fclose(mf);
jsmn_parser modp;
jsmn_init(&modp);
jsmntok_t toks[MOD_MAX * JSON_ELE_MAX];
int r = jsmn_parse(&modp, filebuf, strlen(filebuf), toks, sizeof(toks) / sizeof(toks[0]));
if (r < 0) {
debuglog("jsmn_parse: invalid JSON?\n");
return -1;
}
int nmods = 0;
for (int i = 0; i < r; i++) {
assert(toks[i].type == JSMN_OBJECT);
char mname[MOD_NAME_MAX] = { 0 };
char mpath[MOD_PATH_MAX] = { 0 };
i32 nargs = 0;
u32 udp_port = 0;
i32 isactive = 0;
for (int j = 1; j < (toks[i].size * 2); j+=2) {
char val[256] = { 0 }, key[32] = { 0 };
sprintf(val, "%.*s", toks[j + i + 1].end - toks[j + i + 1].start, filebuf + toks[j + i + 1].start);
sprintf(key, "%.*s", toks[j + i].end - toks[j + i].start, filebuf + toks[j + i].start);
if (strcmp(key, "name") == 0) {
strcpy(mname, val);
} else if (strcmp(key, "path") == 0) {
strcpy(mpath, val);
} else if (strcmp(key, "port") == 0) {
udp_port = atoi(val);
} else if (strcmp(key, "argsize") == 0) {
nargs = atoi(val);
} else if (strcmp(key, "active") == 0) {
isactive = (strcmp(val, "yes") == 0);
} else {
debuglog("Invalid (%s,%s)\n", key, val);
}
}
i += (toks[i].size * 2);
// do not load if it is not active
if (isactive == 0) continue;
struct module *m = module_alloc(mname, mpath, udp_port, nargs, 0, 0, 0, 0);
assert(m);
nmods++;
}
free(filebuf);
assert(nmods);
debuglog("Loaded %d module%s!\n", nmods, nmods > 1 ? "s" : "");
return 0;
}
/*
* TEST data file should contain:
* module_name:<arg1,arg2,arg3...>
* and if your arg has to contain a ',', woops i can't deal with that for now!
* if the first character in a line is ";", then the line is ignored!
*/
int
parse_sandbox_file_custom(char *filename)
{
FILE *mf = fopen(filename, "r");
char buff[UTIL_MOD_LINE_MAX] = { 0 };
int total_boxes = 0;
if (!mf) {
perror("fopen");
return -1;
}
while (fgets(buff, UTIL_MOD_LINE_MAX, mf) != NULL) {
char mname[MOD_NAME_MAX] = { 0 };
char *tok = NULL, *src = buff;
struct module *mod = NULL;
struct sandbox *sb = NULL;
char *args = NULL;
src = util_remove_spaces(src);
if (src[0] == ';') goto next;
if ((tok = strtok_r(src, ":", &src))) {
int ntoks = 0;
strncpy(mname, tok, MOD_NAME_MAX);
mod = module_find(mname);
assert(mod);
if (mod->nargs > 0) {
args = (char *)malloc(mod->nargs * MOD_ARG_MAX_SZ);
assert(args);
while ((tok = strtok_r(src, ",", &src))) {
strncpy(args + (ntoks * MOD_ARG_MAX_SZ), tok, MOD_ARG_MAX_SZ);
ntoks++;
assert(ntoks < MOD_MAX_ARGS);
}
}
} else {
assert(0);
}
sb = sandbox_alloc(mod, args);
assert(sb);
total_boxes++;
next:
memset(buff, 0, UTIL_MOD_LINE_MAX);
}
assert(total_boxes);
debuglog("Instantiated %d sandbox%s!\n", total_boxes, total_boxes > 1 ? "es" : "");
return 0;
}
struct sandbox *
util_parse_sandbox_string_json(struct module *mod, char *str)
{
jsmn_parser sp;
jsmntok_t tk[JSON_ELE_MAX];
jsmn_init(&sp);
int r = jsmn_parse(&sp, str, strlen(str), tk, sizeof(tk)/sizeof(tk[0]));
if (r < 1) {
debuglog("Failed to parse string:%s\n", str);
return NULL;
}
if (tk[0].type != JSMN_OBJECT) return NULL;
for (int j = 1; j < r; j++) {
char key[32] = { 0 };
sprintf(key, "%.*s", tk[j].end - tk[j].start, str + tk[j].start);
if (strcmp(key, "module") == 0) {
char name[32] = { 0 };
sprintf(name, "%.*s", tk[j + 1].end - tk[j + 1].start, str + tk[j + 1].start);
if (strcmp(name, mod->name) != 0) return NULL;
j++;
} else if (strcmp(key, "args") == 0) {
if (tk[j + 1].type != JSMN_ARRAY) return NULL;
char *args = malloc(tk[j + 1].size * MOD_ARG_MAX_SZ);
assert(args);
for (int k = 1; k <= tk[j + 1].size; k++) {
jsmntok_t *g = &tk[j + k + 1];
strncpy(args + ((k - 1) * MOD_ARG_MAX_SZ), str + g->start, g->end - g->start);
*(args + ((k - 1) * MOD_ARG_MAX_SZ) + g->end - g->start) = '\0';
}
struct sandbox *sb = sandbox_alloc(mod, args);
assert(sb);
return sb;
} else {
return NULL;
}
}
return NULL;
}
struct sandbox *
util_parse_sandbox_string_custom(struct module *mod, char *str)
{
char *tok = NULL, *src = str;
src = util_remove_spaces(src);
if (src[0] == ';') return NULL;
if (!(tok = strtok_r(src, ":", &src))) return NULL;
if (strcmp(mod->name, tok)) return NULL;
// struct module *mod = module_find(tok);
// if (!mod) return NULL;
assert(mod->nargs >= 0 && mod->nargs < MOD_MAX_ARGS);
char *args = (char *)malloc(mod->nargs * MOD_ARG_MAX_SZ);
assert(args);
int ntoks = 0;
while ((tok = strtok_r(src, ",", &src))) {
strncpy(args + (ntoks * MOD_ARG_MAX_SZ), tok, MOD_ARG_MAX_SZ);
ntoks++;
assert(ntoks < MOD_MAX_ARGS);
}
struct sandbox *sb = sandbox_alloc(mod, args);
assert(sb);
return sb;
}
/*
* Each line in the file should be like:
*
* module_path:module_name:module_nargs:module_stack_size:module_max_heap_size[:moreargs::argn\n]
* if the first character in a line is ";", then the line is ignored!
*/
int
util_parse_modules_file_custom(char *filename)
{
FILE *mf = fopen(filename, "r");
char buff[UTIL_MOD_LINE_MAX] = { 0 };
int nmods = 0;
if (!mf) {
perror("fopen");
return -1;
}
while (fgets(buff, UTIL_MOD_LINE_MAX, mf) != NULL) {
char mname[MOD_NAME_MAX] = { 0 };
char mpath[MOD_PATH_MAX] = { 0 };
i32 nargs = 0;
u32 stack_sz = 0;
u32 max_heap = 0;
u32 timeout = 0;
char *tok = NULL, *src = buff;
u32 udp_port = 0;
i32 ntoks = 0;
src = util_remove_spaces(src);
if (src[0] == ';') goto next;
while ((tok = strtok_r(src, ":", &src))) {
switch(ntoks) {
case MOD_ARG_MODPATH: strncpy(mpath, tok, MOD_PATH_MAX); break;
case MOD_ARG_MODPORT: udp_port = atoi(tok);
case MOD_ARG_MODNAME: strncpy(mname, tok, MOD_NAME_MAX); break;
case MOD_ARG_MODNARGS: nargs = atoi(tok); break;
default: break;
}
ntoks++;
}
assert(ntoks >= MOD_ARG_MAX);
struct module *m = module_alloc(mname, mpath, udp_port, nargs, 0, 0, 0, 0);
assert(m);
nmods++;
next:
memset(buff, 0, UTIL_MOD_LINE_MAX);
}
assert(nmods);
debuglog("Loaded %d module%s!\n", nmods, nmods > 1 ? "s" : "");
fclose(mf);
return 0;
}

@ -0,0 +1,51 @@
include Makefile.inc
BENCH_DIR=../../silverfish/code_benches/
TESTS=forever filesys sockserver sockclient
TESTSRT=$(TESTS:%=%_rt)
BENCHES=adpcm basic_math binarytrees bitcount blowfish crc dijkstra fft function_pointers \
gsm libjpeg mandelbrot patricia pgp qsort rsynth sha sqlite stringsearch susan
BENCHESSF=$(BENCHES:%=%_sf)
adpcm_CFLAGS=-Wno-implicit-int -Wno-implicit-function-declaration
crc_CFLAGS=-Wno-implicit-int -Wno-format
dijkstra_CFLAGS=-Wno-return-type
gsm_CFLAGS=-DSASR -Wno-everything
libjpeg_CFLAGS=-Wno-incompatible-library-redeclaration -Wno-implicit-function-declaration -Wno-shift-negative-value
pgp_CFLAGS=-DUNIX -D_BSD -DPORTABLE -DUSE_NBIO -DMPORTABLE -I${BENCH_DIR}/pgp/ -Wno-everything
rsynth_CFLAGS=-I${BENCH_DIR}/rsynth -Wno-everything -I/usr/local/include
sha_CLFAGS=-Wno-everything
susan_CFLAGS=-Wno-everything
.PHONY: all clean rttests sftests
sftests: $(BENCHESSF)
rttests: $(TESTSRT)
all: rttests sftests
@echo "Compilation done!"
clean:
@rm -rf ${TMP_DIR}
@rm -f ${BIN_DIR}/*_wasm.so
%_sf:
@mkdir -p ${TMP_DIR}
@echo "Compiling $(@:%_sf=%)"
${WASMCC} ${$(@:%_sf=%)_CFLAGS} ${WASMCFLAGS} ${OPTFLAGS} ${BENCH_DIR}/$(@:%_sf=%)/*.c -o ${TMP_DIR}/$(@:%_sf=%).wasm
${SFCC} ${TMP_DIR}/$(@:%_sf=%).wasm -o ${TMP_DIR}/$(@:%_sf=%).bc
${CC} --shared -fPIC ${OPTFLAGS} -I${RT_INC} -D${USE_MEM} ${TMP_DIR}/$(@:%_sf=%).bc ${MEMC} ${WASMISA} -o ${TMP_DIR}/$(@:%_sf=%)_wasm.so
@cp ${TMP_DIR}/$(@:%_sf=%)_wasm.so ${BIN_DIR}
@rm -rf ${TMP_DIR}
%_rt:
@mkdir -p ${TMP_DIR}
@echo "Compiling $(@:%_rt=%)"
${WASMCC} ${$(@:%_rt=%)_CFLAGS} ${WASMCFLAGS} ${OPTFLAGS} $(@:%_rt=%)/*.c -o ${TMP_DIR}/$(@:%_rt=%).wasm
${SFCC} ${TMP_DIR}/$(@:%_rt=%).wasm -o ${TMP_DIR}/$(@:%_rt=%).bc
${CC} --shared -fPIC ${OPTFLAGS} -I${RT_INC} -D${USE_MEM} ${TMP_DIR}/$(@:%_rt=%).bc ${MEMC} ${WASMISA} -o ${TMP_DIR}/$(@:%_rt=%)_wasm.so
@cp ${TMP_DIR}/$(@:%_rt=%)_wasm.so ${BIN_DIR}
@rm -rf ${TMP_DIR}

@ -0,0 +1,22 @@
BASE=awsm
SFCC=silverfish
CC=clang
WASMCC=wasm32-unknown-unknown-wasm-clang
OPTFLAGS=-O3 -flto
#same stack-size for all
WASMLINKFLAGS=-Wl,-z,stack-size=524288,--allow-undefined,--no-threads,--stack-first,--no-entry,--export-all,--export=main,--export=dummy
WASMCFLAGS=${WASMLINKFLAGS} -nostartfiles
BASE_DIR=../../
RT_DIR=${BASE_DIR}/runtime/
RT_INC=${RT_DIR}/include/
USE_MEM=USE_MEM_VM
ifeq ($(USE_MEM),USE_MEM_VM)
MEMC=${RT_DIR}/compiletime/memory/64bit_nix.c
endif
BIN_DIR=${RT_DIR}/bin/
TMP_DIR=tmp/

@ -0,0 +1,118 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/uio.h>
#define BUF_MAX 44
#define RDWR_MAX 1
#if RDWR_MAX > 1
int main(int argc, char **argv) __attribute__ ((optnone))
{
char buf[RDWR_MAX][BUF_MAX] = { 0 };
printf("%s enter [in:%s, out:%s]\n", argv[0], argv[1], argv[2]);
int fdr = open(argv[1], O_RDONLY, S_IRUSR | S_IRGRP);
if (fdr < 0) {
perror("fopen");
return -1;
}
int fdw = creat(argv[2], S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
if (fdw < 0) {
perror("creat");
return -1;
}
int n = 0;
struct iovec iov[RDWR_MAX] = { 0 };
for (int i = 0; i < RDWR_MAX; i++) {
iov[i].iov_base = buf[i];
iov[i].iov_len = BUF_MAX;
}
while ((n = readv(fdr, iov, RDWR_MAX)) > 0) {
int wvcnt = n / BUF_MAX;
if (n % BUF_MAX) {
iov[wvcnt].iov_len = n % BUF_MAX;
wvcnt++;
}
if (writev(fdw, iov, wvcnt) != n) perror("writev");
memset(buf, 0, RDWR_MAX * BUF_MAX);
for (int i = 0; i < RDWR_MAX; i++) {
iov[i].iov_base = buf[i];
iov[i].iov_len = BUF_MAX;
}
n = 0;
}
close(fdr);
close(fdw);
printf("%s done\n", argv[0]);
return 0;
}
#else
int
main(int argc, char **argv) __attribute__ ((optnone))
{
char buf[BUF_MAX] = { 0 };
printf("%s enter [in:%s, out:%s]\n", argv[0], argv[1], argv[2]);
#ifdef USE_OPEN
int fdr = open(argv[1], O_RDONLY, S_IRUSR | S_IRGRP);
if (fdr < 0) {
perror("fopen");
return -1;
}
int fdw = creat(argv[2], S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
if (fdw < 0) {
perror("creat");
return -1;
}
int n = 0;
while ((n = read(fdr, buf, BUF_MAX)) > 0) {
if (write(fdw, buf, n) != n) perror("write");
memset(buf, 0, BUF_MAX);
n = 0;
}
if (n < 0) perror("read");
close(fdr);
close(fdw);
#else
FILE *fpr = fopen(argv[1], "r");
if (!fpr) {
perror("fopen");
return -1;
}
FILE *fpw = fopen(argv[2], "w");
if (!fpw) {
perror("fopen");
return -1;
}
while (!feof(fpr)) {
char *p = NULL;
if ((p = fgets(buf, BUF_MAX, fpr)) == NULL) perror("fgets");
else {
if (fputs(p, fpw) < 0) perror("fputs");
p = NULL;
}
memset(buf, 0, BUF_MAX);
}
fclose(fpr);
fclose(fpw);
#endif
printf("%s done\n", argv[0]);
return 0;
}
#endif

@ -0,0 +1,27 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define ITERS 50000000
int
main(int argc, char **argv) __attribute__ ((optnone))
{
printf("%s enter\n", argv[0]);
int n = 0, e = 1;
if (argc == 2) {
n = atoi(argv[1]);
if (n > 0) e = 0;
}
while (e || n > 0) {
int i = ITERS;
n--;
while (i-- > 0) {
int j = ITERS;
while (j-- > 0) __asm__ __volatile__("nop": : :"memory");
}
printf("%s\n", argv[0]);
}
printf("%s done\n", argv[0]);
}

@ -0,0 +1,55 @@
/* code from http://www.cs.rpi.edu/~moorthy/Courses/os98/Pgms/socket.html */
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
void error(char *msg)
{
perror(msg);
exit(0);
}
int main(int argc, char *argv[])
{
int sockfd, portno, n;
struct sockaddr_in serv_addr;
struct hostent *server;
char buffer[256] = "The quick brown fox jumps over the lazy dog";
if (argc < 3) {
fprintf(stderr,"usage %s hostname port\n", argv[0]);
exit(0);
}
portno = atoi(argv[2]);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
server = gethostbyname(argv[1]);
if (server == NULL) {
fprintf(stderr,"ERROR, no such host\n");
exit(0);
}
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
bcopy((char *)server->h_addr,
(char *)&serv_addr.sin_addr.s_addr,
server->h_length);
serv_addr.sin_port = htons(portno);
if (connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0)
error("ERROR connecting");
printf("Sending message %s\n", buffer);
n = send(sockfd,buffer,strlen(buffer), 0);
if (n < 0)
error("ERROR writing to socket");
bzero(buffer,256);
n = recv(sockfd,buffer,255, 0);
if (n < 0)
error("ERROR reading from socket");
printf("%s\n",buffer);
close(sockfd);
return 0;
}

@ -0,0 +1,51 @@
/* A simple server in the internet domain using TCP
The port number is passed as an argument */
/* code from: http://www.cs.rpi.edu/~moorthy/Courses/os98/Pgms/socket.html */
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
void error(char *msg)
{
perror(msg);
exit(1);
}
int main(int argc, char *argv[])
{
int sockfd, newsockfd, portno, clilen;
char buffer[256];
struct sockaddr_in serv_addr, cli_addr;
int n;
if (argc < 2) {
fprintf(stderr,"ERROR, no port provided\n");
exit(1);
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = atoi(argv[1]);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
if (bind(sockfd, (struct sockaddr *) &serv_addr,
sizeof(serv_addr)) < 0)
error("ERROR on binding");
listen(sockfd,5);
clilen = sizeof(cli_addr);
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
if (newsockfd < 0)
error("ERROR on accept");
bzero(buffer,256);
n = recv(newsockfd,buffer,255, 0);
if (n < 0) error("ERROR reading from socket");
printf("Here is the message: %s\n",buffer);
n = send(newsockfd,"I got your message",18, 0);
if (n < 0) error("ERROR writing to socket");
close(newsockfd);
close(sockfd);
return 0;
}

@ -0,0 +1,133 @@
{
"active" : "no",
"name" : "adpcm",
"path" : "adpcm_wasm.so",
"port" : 10000,
"argsize" : 2
},
{
"active" : "no",
"name" : "bitcount",
"path" : "bitcount_wasm.so",
"port" : 10002,
"argsize" : 2
},
{
"active" : "no",
"name" : "basic_math",
"path" : "basic_math_wasm.so",
"port" : 10004,
"argsize" : 1
},
{
"active" : "no",
"name" : "binarytrees",
"path" : "binarytrees_wasm.so",
"port" : 10006,
"argsize" : 2
},
{
"active" : "no",
"name" : "crc",
"path" : "crc_wasm.so",
"port" : 10008,
"argsize" : 2
},
{
"active" : "no",
"name" : "dijkstra",
"path" : "dijkstra_wasm.so",
"port" : 10010,
"argsize" : 2
},
{
"active" : "no",
"name" : "forever",
"path" : "forever_wasm.so",
"port" : 10012,
"argsize" : 1
},
{
"active" : "no",
"name" : "fornever",
"path" : "forever_wasm.so",
"port" : 10014,
"argsize" : 2
},
{
"active" : "no",
"name" : "fft",
"path" : "fft_wasm.so",
"port" : 10016,
"argsize" : 3
},
{
"active" : "no",
"name" : "function_pointers",
"path" : "function_pointers_wasm.so",
"port" : 10018,
"argsize" : 1
},
{
"active" : "no",
"name" : "gsm",
"path" : "gsm_wasm.so",
"port" : 10020,
"argsize" : 4
},
{
"active" : "no",
"name" : "libjpeg",
"path" : "libjpeg_wasm.so",
"port" : 10022,
"argsize" : 1
},
{
"active" : "no",
"name" : "mandelbrot",
"path" : "mandelbrot_wasm.so",
"port" : 10024,
"argsize" : 2
},
{
"active" : "no",
"name" : "matrix_multiply",
"path" : "matrix_multiply_wasm.so",
"port" : 10026,
"argsize" : 1
},
{
"active" : "no",
"name" : "particia",
"path" : "partricia_wasm.so",
"port" : 10028,
"argsize" : 2
},
{
"active" : "no",
"name" : "sqlite",
"path" : "sqlite_wasm.so",
"port" : 10030,
"argsize" : 1
},
{
"active" : "no",
"name" : "filesys",
"path" : "filesys_wasm.so",
"port" : 10032,
"argsize" : 3
},
{
"active" : "yes",
"name" : "sockserver",
"path" : "sockserver_wasm.so",
"port" : 10034,
"argsize" : 2
},
{
"active" : "yes",
"name" : "sockclient",
"path" : "sockclient_wasm.so",
"port" : 10036,
"argsize" : 3
}

@ -0,0 +1,16 @@
adpcm_wasm.so:10000:adpcm:2:0:0:0:0
bitcount_wasm.so:10002:bitcount:2:0:0:0:0
basic_math_wasm.so:10004:basic_math:1:0:0:0:0
binarytrees_wasm.so:10006:binarytrees:2:0:0:0:0
crc_wasm.so:10008:crc:2:0:0:0:0
;dijkstra_wasm.so:10010:dijkstra:2:0:0:0:0
forever_wasm.so:10012:forever:1:0:0:0:0
forever_wasm.so:10014:fornever:2:0:0:0:0
;fft_wasm.so:10016:fft:3:0:0:0:0
function_pointers_wasm.so:10018:function_pointers:1:0:0:0:0
gsm_wasm.so:10020:gsm:4:0:0:0:0
;libjpeg_wasm.so:10022:libjpeg:1:0:0:0:0
mandelbrot_wasm.so:10024:mandelbrot:2:0:0:0:0
;matrix_multiply_wasm.so:10026:matrix_multiply:1:0:0:0:0
patricia_wasm.so:10028:patricia:2:0:0:0:0
sqlite_wasm.so:10030:sqlite:1:0:0:0:0

@ -0,0 +1,34 @@
;127.0.0.1:10002${ "module" : "bitcount", "args" : [ "bitcount1" , "16777216" ] }
;127.0.0.1:10002${ "module" : "bitcount", "args" : [ "bitcount2" , "16777216" ] }
;127.0.0.1:10004${ "module" : "basic_math", "args" : [ "basic_math1" ] }
;127.0.0.1:10004${ "module" : "basic_math", "args" : [ "basic_math2" ] }
;127.0.0.1:10006${ "module" : "binarytrees", "args" : [ "binarytrees1", "16" ] }
;127.0.0.1:10006${ "module" : "binarytrees", "args" : [ "binarytrees2", "16" ] }
;127.0.0.1:10008${ "module" : "crc", "args" : [ "crc1", "crc/large.pcm" ] }
;127.0.0.1:10008${ "module" : "crc", "args" : [ "crc2", "crc/large.pcm" ] }
;127.0.0.1:10010${ "module" : "dijkstra", "args" : [ "dijkstra1", "dijkstra/input.dat" ] }
;127.0.0.1:10010${ "module" : "dijkstra", "args" : [ "dijkstra2", "dijkstra/input.dat" ] }
;127.0.0.1:10012${ "module" : "forever", "args" : [ "forever01" ] }
;127.0.0.1:10012${ "module" : "forever", "args" : [ "forever02" ] }
;127.0.0.1:10014${ "module" : "fornever", "args" : [ "fornever01", "10" ] }
;127.0.0.1:10014${ "module" : "fornever", "args" : [ "fornever02", "20" ] }
;127.0.0.1:10014${ "module" : "fornever", "args" : [ "fornever03", "30" ] }
;127.0.0.1:10014${ "module" : "fornever", "args" : [ "fornever04", "40" ] }
;127.0.0.1:10016${ "module" : "fft", "args" : [ "fft1" , "8", "32768" ] }
;127.0.0.1:10016${ "module" : "fft", "args" : [ "fft2" , "8", "32768" ] }
;127.0.0.1:10018${ "module" : "function_pointers", "args" : [ "function_pointers1" ] }
;127.0.0.1:10018${ "module" : "function_pointers", "args" : [ "function_pointers2" ] }
;127.0.0.1:10020${ "module" : "gsm", "args" : [ "gsm1" , "-fps" , "-c", "gsm/large.au" ] }
;127.0.0.1:10020${ "module" : "gsm", "args" : [ "gsm2" , "-fps" , "-c", "gsm/large.au" ] }
;127.0.0.1:10022${ "module" : "libjpeg", "args" : [ "libjpeg1" ] }
;127.0.0.1:10022${ "module" : "libjpeg", "args" : [ "libjpeg2" ] }
;127.0.0.1:10024${ "module" : "mandelbrot", "args" : [ "mandelbrot1", "5000" ] }
;127.0.0.1:10024${ "module" : "mandelbrot", "args" : [ "mandelbrot2", "5000" ] }
;127.0.0.1:10026${ "module" : "matrix_multiply", "args" : [ "matrix_multiply1" ] }
;127.0.0.1:10026${ "module" : "matrix_multiply", "args" : [ "matrix_multiply2" ] }
;127.0.0.1:10028${ "module" : "patricia", "args" : [ "patricia1" , "large.udp" ] }
;127.0.0.1:10030${ "module" : "sqlite", "args" : [ "sqlite1" ] }
;127.0.0.1:10030${ "module" : "sqlite", "args" : [ "sqlite2" ] }
;127.0.0.1:10032${ "module" : "filesys", "args" : [ "filesys1", "fs_in.txt", "fs_out.txt" ] }
127.0.0.1:10034${ "module" : "sockserver", "args" : [ "sockserv1", "20000" ] }
127.0.0.1:10036${ "module" : "sockclient", "args" : [ "sockcli1", "localhost", "20000" ] }

@ -0,0 +1,33 @@
10002$bitcount:bitcount1,16777216
10002$bitcount:bitcount2,16777216
10004$basic_math:basic_math1
10004$basic_math:basic_math2
10006$binarytrees:binarytrees1,16
10006$binarytrees:binarytrees2,16
10008$crc:crc1,crc/large.pcm
10008$crc:crc2,crc/large.pcm
;10010$dijkstra:dijkstra1,dijkstra/input.dat
;10010$dijkstra:dijkstra2,dijkstra/input.dat
;10012$forever:forever01
;10012$forever:forever02
10014$fornever:fornever01,10
10014$fornever:fornever02,20
;10012$forever:forever03
;10012$forever:forever04
10014$fornever:fornever03,30
10014$fornever:fornever04,40
;10016$fft:fft1,8,32768
;10016$fft:fft2,8,32768
;10018$function_pointers:function_pointers1
;10018$function_pointers:function_pointers2
;10020$gsm:gsm1,-fps,-c,gsm/large.au
;10020$gsm:gsm2,-fps,-c,gsm/large.au
;10022$libjpeg:libjpeg1
;10022$libjpeg:libjpeg2
;10024$mandelbrot:mandelbrot1,5000
;10024$mandelbrot:mandelbrot2,5000
;10026$matrix_multiply:matrix_multiply1
;10026$matrix_multiply:matrix_multiply2
;10028$patricia:patricia1,large.udp
;10030$sqlite:sqlite1
;10030$sqlite:sqlite2

@ -0,0 +1,13 @@
SUBDIRS=$(wildcard */)
dirs:
@for dir in $(SUBDIRS) ; do \
$(MAKE) -C $$dir ; \
done
clean:
@for dir in $(SUBDIRS) ; do \
$(MAKE) -C $$dir clean ; \
done
all: clean dirs

@ -0,0 +1,9 @@
udp: udpclient.c
@echo "Compiling udpclient"
@gcc udpclient.c -o ../../bin/udpclient
clean:
@echo "Cleaning up udpclient"
@rm -f ../../bin/udpclient
all: clean udp

@ -0,0 +1,102 @@
#include <ctype.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <malloc.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/time.h>
#include <signal.h>
#include <time.h>
#define MSG_MAX 1024
static char *
remove_spaces(char *str)
{
int i = 0;
while (isspace(*str)) str++;
i = strlen(str);
while (isspace(str[i-1])) str[i-1]='\0';
return str;
}
int main(int argc, char *argv[])
{
if (argc != 2) {
printf("Usage: %s <sandbox_file>\n", argv[0]);
return -1;
}
FILE *f = fopen(argv[1], "r");
if (!f) {
perror("fopen");
return -1;
}
while (1) {
fseek(f, 0, SEEK_SET);
char line[MSG_MAX] = { 0 };
while (fgets(line, MSG_MAX, f) != NULL) {
int fd = -1;
struct sockaddr_in sa;
char *msg = NULL, *tok, *src = line;
char ip[32] = { 0 }, port[32] = { 0 };
src = remove_spaces(src);
if (src[0] == ';') goto next;
tok = strtok_r(src, ":", &src);
strcpy(ip, tok);
tok = strtok_r(src, "$", &src);
strcpy(port, tok);
msg = src;
int i = 0;
printf("\nRequest [%s] to [%s:%d]\n (1:Proceed 2:Skip ANY:Exit) ", msg, ip, atoi(port));
scanf("%d", &i);
if (i <= 0 || i > 2) {
printf("Exiting!\n");
exit(0);
} else if (i == 1) {
printf("Proceeding!\n");
} else {
printf("Skipping!\n");
goto next;
}
sa.sin_family = AF_INET;
sa.sin_port = htons(atoi(port));
sa.sin_addr.s_addr = inet_addr(ip);
if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1) {
perror("Establishing socket");
return -1;
}
if (sendto(fd, msg, strlen(msg), 0, (struct sockaddr*)&sa, sizeof(sa)) < 0 &&
errno != EINTR) {
perror("sendto");
return -1;
}
printf("Done!\n");
next:
memset(line, 0, MSG_MAX);
fflush(stdin);
fflush(stdout);
if (fd >= 0) close(fd);
}
}
fclose(f);
return 0;
}

@ -0,0 +1 @@
Subproject commit 015e2bb638d47a793d0da96bb4b697be9d010209
Loading…
Cancel
Save