1
0
Fork 0
mirror of https://github.com/ossrs/srs.git synced 2025-02-15 04:42:04 +00:00

Merge branch 'develop' into merge/develop

This commit is contained in:
winlin 2021-05-19 21:04:34 +08:00
commit 3f3c62b673
37 changed files with 116 additions and 6176 deletions

View file

@ -177,6 +177,7 @@ The ports used by SRS:
## V5 changes
* v5.0, 2021-05-19, ST: Simplify it, only Linux/Darwin, epoll/kqueue, single process. 5.0.2
* v5.0, 2021-03-17, Live: Refine edge to follow client and HTTP/302. 5.0.1
* v5.0, 2021-03-15, Init SRS/5. 5.0.0

View file

@ -38,20 +38,8 @@ VERSION = 1.9
##########################
# Supported OSes:
#
#OS = AIX
#OS = CYGWIN
#OS = DARWIN
#OS = FREEBSD
#OS = HPUX
#OS = HPUX_64
#OS = IRIX
#OS = IRIX_64
#OS = LINUX
#OS = NETBSD
#OS = OPENBSD
#OS = OSF1
#OS = SOLARIS
#OS = SOLARIS_64
# Please see the "Other possible defines" section below for
# possible compilation options.
@ -62,6 +50,7 @@ AR = ar
LD = ld
RANLIB = ranlib
LN = ln
STATIC_ONLY = yes
SHELL = /bin/sh
ECHO = /bin/echo
@ -72,7 +61,7 @@ TARGETDIR = $(OS)_$(shell uname -r)_$(BUILD)
DEFINES = -D$(OS)
CFLAGS =
SFLAGS =
ARFLAGS = -rv
ARFLAGS = -r
LNFLAGS = -s
DSO_SUFFIX = so
@ -83,20 +72,8 @@ DESC = st.pc
# Platform section.
# Possible targets:
TARGETS = aix-debug aix-optimized \
cygwin-debug cygwin-optimized \
darwin-debug darwin-optimized \
freebsd-debug freebsd-optimized \
hpux-debug hpux-optimized \
hpux-64-debug hpux-64-optimized \
irix-n32-debug irix-n32-optimized \
irix-64-debug irix-64-optimized \
linux-debug linux-optimized \
netbsd-debug netbsd-optimized \
openbsd-debug openbsd-optimized \
osf1-debug osf1-optimized \
solaris-debug solaris-optimized \
solaris-64-debug solaris-64-optimized
TARGETS = darwin-debug darwin-optimized \
linux-debug linux-optimized
UTEST_TARGETS = darwin-debug-utest linux-debug-utest \
darwin-debug-gcov linux-debug-gcov
@ -105,128 +82,25 @@ UTEST_TARGETS = darwin-debug-utest linux-debug-utest \
# Platform specifics
#
ifeq ($(OS), AIX)
AIX_VERSION = $(shell uname -v).$(shell uname -r)
TARGETDIR = $(OS)_$(AIX_VERSION)_$(BUILD)
CC = xlC
STATIC_ONLY = yes
ifeq ($(BUILD), OPT)
OTHER_FLAGS = -w
endif
ifneq ($(filter-out 4.1 4.2, $(AIX_VERSION)),)
DEFINES += -DMD_HAVE_SOCKLEN_T
endif
endif
ifeq ($(OS), CYGWIN)
TARGETDIR = $(OS)_$(BUILD)
CC = gcc
LD = gcc
DSO_SUFFIX = dll
SLIBRARY = $(TARGETDIR)/libst.dll.a
DLIBRARY = $(TARGETDIR)/libst.dll
DEF_FILE = $(TARGETDIR)/libst.def
LDFLAGS = libst.def -shared --enable-auto-image-base -Wl,--output-def,$(DEF_FILE),--out-implib,$(SLIBRARY)
OTHER_FLAGS = -Wall
endif
ifeq ($(OS), DARWIN)
EXTRA_OBJS = $(TARGETDIR)/md_darwin.o
LD = cc
SFLAGS = -fPIC -fno-common
DSO_SUFFIX = dylib
RELEASE = $(shell uname -r | cut -d. -f1)
PPC = $(shell test $(RELEASE) -le 9 && echo yes)
INTEL = $(shell test $(RELEASE) -ge 9 && echo yes)
ifeq ($(PPC), yes)
CFLAGS += -arch ppc
LDFLAGS += -arch ppc
endif
ifeq ($(INTEL), yes)
CFLAGS += -arch x86_64
LDFLAGS += -arch x86_64
endif
LDFLAGS += -dynamiclib -install_name /sw/lib/libst.$(MAJOR).$(DSO_SUFFIX) -compatibility_version $(MAJOR) -current_version $(VERSION)
OTHER_FLAGS = -Wall
endif
ifeq ($(OS), FREEBSD)
SFLAGS = -fPIC
LDFLAGS = -shared -soname=$(SONAME) -lc
OTHER_FLAGS = -Wall
ifeq ($(shell test -f /usr/include/sys/event.h && echo yes), yes)
DEFINES += -DMD_HAVE_KQUEUE
endif
endif
ifeq (HPUX, $(findstring HPUX, $(OS)))
ifeq ($(OS), HPUX_64)
DEFINES = -DHPUX
CFLAGS = -Ae +DD64 +Z
else
CFLAGS = -Ae +DAportable +Z
endif
RANLIB = true
LDFLAGS = -b
DSO_SUFFIX = sl
endif
ifeq (IRIX, $(findstring IRIX, $(OS)))
ifeq ($(OS), IRIX_64)
DEFINES = -DIRIX
ABIFLAG = -64
else
ABIFLAG = -n32
endif
RANLIB = true
CFLAGS = $(ABIFLAG) -mips3
LDFLAGS = $(ABIFLAG) -shared
OTHER_FLAGS = -fullwarn
endif
ifeq ($(OS), LINUX)
EXTRA_OBJS = $(TARGETDIR)/md.o
EXTRA_OBJS = $(TARGETDIR)/md_linux.o
SFLAGS = -fPIC
LDFLAGS = -shared -soname=$(SONAME) -lc
OTHER_FLAGS = -Wall
ifeq ($(shell test -f /usr/include/sys/epoll.h && echo yes), yes)
DEFINES += -DMD_HAVE_EPOLL
endif
endif
ifeq ($(OS), NETBSD)
SFLAGS = -fPIC
LDFLAGS = -shared -soname=$(SONAME) -lc
OTHER_FLAGS = -Wall
endif
ifeq ($(OS), OPENBSD)
SFLAGS = -fPIC
LDFLAGS = -shared -soname=$(SONAME) -lc
OTHER_FLAGS = -Wall
ifeq ($(shell test -f /usr/include/sys/event.h && echo yes), yes)
DEFINES += -DMD_HAVE_KQUEUE
endif
endif
ifeq ($(OS), OSF1)
RANLIB = true
LDFLAGS = -shared -all -expect_unresolved "*"
endif
ifeq (SOLARIS, $(findstring SOLARIS, $(OS)))
TARGETDIR = $(OS)_$(shell uname -r | sed 's/^5/2/')_$(BUILD)
CC = gcc
LD = gcc
RANLIB = true
LDFLAGS = -G
OTHER_FLAGS = -Wall
ifeq ($(OS), SOLARIS_64)
DEFINES = -DSOLARIS
CFLAGS += -m64
LDFLAGS += -m64
endif
endif
#
# End of platform section.
@ -234,9 +108,9 @@ endif
ifeq ($(BUILD), OPT)
OTHER_FLAGS += -O
OTHER_FLAGS += -O2
else
OTHER_FLAGS += -g
OTHER_FLAGS += -g -O0
DEFINES += -DDEBUG
endif
@ -285,10 +159,6 @@ endif
#
# make EXTRA_CFLAGS=-UMD_HAVE_EPOLL <target>
#
# or to enable sendmmsg(2) support:
#
# make EXTRA_CFLAGS="-DMD_HAVE_SENDMMSG -D_GNU_SOURCE"
#
# or to enable stats for ST:
#
# make EXTRA_CFLAGS=-DDEBUG_STATS
@ -311,28 +181,11 @@ OBJS += $(EXTRA_OBJS)
HEADER = $(TARGETDIR)/st.h
SLIBRARY = $(TARGETDIR)/libst.a
DLIBRARY = $(TARGETDIR)/libst.$(DSO_SUFFIX).$(VERSION)
EXAMPLES = examples
LINKNAME = libst.$(DSO_SUFFIX)
SONAME = libst.$(DSO_SUFFIX).$(MAJOR)
FULLNAME = libst.$(DSO_SUFFIX).$(VERSION)
ifeq ($(OS), CYGWIN)
SONAME = cygst.$(DSO_SUFFIX)
SLIBRARY = $(TARGETDIR)/libst.dll.a
DLIBRARY = $(TARGETDIR)/$(SONAME)
LINKNAME =
# examples directory does not compile under cygwin
EXAMPLES =
endif
# for SRS
# disable examples for ubuntu crossbuild failed.
# @see https://github.com/winlinvip/simple-rtmp-server/issues/308
ifeq ($(OS), LINUX)
EXAMPLES =
endif
ifeq ($(OS), DARWIN)
LINKNAME = libst.$(DSO_SUFFIX)
SONAME = libst.$(MAJOR).$(DSO_SUFFIX)
@ -348,7 +201,7 @@ endif
ifeq ($(OS),)
ST_ALL = unknown
else
ST_ALL = $(TARGETDIR) $(LIBRARIES) $(HEADER) $(EXAMPLES) $(DESC)
ST_ALL = $(TARGETDIR) $(LIBRARIES) $(HEADER) $(DESC)
endif
all: $(ST_ALL)
@ -386,7 +239,7 @@ $(HEADER): public.h
rm -f $@
cp public.h $@
$(TARGETDIR)/md.o: md.S
$(TARGETDIR)/md_linux.o: md_linux.S
$(CC) $(CFLAGS) -c $< -o $@
$(TARGETDIR)/md_darwin.o: md_darwin.S
@ -395,10 +248,6 @@ $(TARGETDIR)/md_darwin.o: md_darwin.S
$(TARGETDIR)/%.o: %.c common.h md.h
$(CC) $(CFLAGS) -c $< -o $@
examples: $(SLIBRARY)
@echo Making $@
@cd $@; $(MAKE) CC="$(CC)" CFLAGS="$(CFLAGS)" OS="$(OS)" TARGETDIR="$(TARGETDIR)"
clean:
rm -rf *_OPT *_DBG obj st.pc
@ -418,80 +267,15 @@ endif
##########################
# Target rules:
default-debug:
. ./osguess.sh; $(MAKE) OS="$$OS" BUILD="DBG"
default default-optimized:
. ./osguess.sh; $(MAKE) OS="$$OS" BUILD="OPT"
aix-debug:
$(MAKE) OS="AIX" BUILD="DBG"
aix-optimized:
$(MAKE) OS="AIX" BUILD="OPT"
cygwin-debug:
$(MAKE) OS="CYGWIN" BUILD="DBG"
cygwin-optimized:
$(MAKE) OS="CYGWIN" BUILD="OPT"
darwin-debug:
$(MAKE) OS="DARWIN" BUILD="DBG"
darwin-optimized:
$(MAKE) OS="DARWIN" BUILD="OPT"
freebsd-debug:
$(MAKE) OS="FREEBSD" BUILD="DBG"
freebsd-optimized:
$(MAKE) OS="FREEBSD" BUILD="OPT"
hpux-debug:
$(MAKE) OS="HPUX" BUILD="DBG"
hpux-optimized:
$(MAKE) OS="HPUX" BUILD="OPT"
hpux-64-debug:
$(MAKE) OS="HPUX_64" BUILD="DBG"
hpux-64-optimized:
$(MAKE) OS="HPUX_64" BUILD="OPT"
irix-n32-debug:
$(MAKE) OS="IRIX" BUILD="DBG"
irix-n32-optimized:
$(MAKE) OS="IRIX" BUILD="OPT"
irix-64-debug:
$(MAKE) OS="IRIX_64" BUILD="DBG"
irix-64-optimized:
$(MAKE) OS="IRIX_64" BUILD="OPT"
linux-debug:
$(MAKE) OS="LINUX" BUILD="DBG"
linux-optimized:
$(MAKE) OS="LINUX" BUILD="OPT"
# compatibility
linux-ia64-debug: linux-debug
linux-ia64-optimized: linux-optimized
netbsd-debug:
$(MAKE) OS="NETBSD" BUILD="DBG"
netbsd-optimized:
$(MAKE) OS="NETBSD" BUILD="OPT"
openbsd-debug:
$(MAKE) OS="OPENBSD" BUILD="DBG"
openbsd-optimized:
$(MAKE) OS="OPENBSD" BUILD="OPT"
osf1-debug:
$(MAKE) OS="OSF1" BUILD="DBG"
osf1-optimized:
$(MAKE) OS="OSF1" BUILD="OPT"
solaris-debug:
$(MAKE) OS="SOLARIS" BUILD="DBG"
solaris-optimized:
$(MAKE) OS="SOLARIS" BUILD="OPT"
solaris-64-debug:
$(MAKE) OS="SOLARIS_64" BUILD="DBG"
solaris-64-optimized:
$(MAKE) OS="SOLARIS_64" BUILD="OPT"
darwin-debug-utest:
@echo "Build utest for state-threads"

View file

@ -68,10 +68,11 @@ The branch [srs](https://github.com/ossrs/state-threads/tree/srs) will be patche
- [x] Support macro `MD_ST_NO_ASM` to disable ASM, [#8](https://github.com/ossrs/state-threads/issues/8).
- [x] Merge patch [srs#1282](https://github.com/ossrs/srs/issues/1282#issuecomment-445539513) to support aarch64, [#9](https://github.com/ossrs/state-threads/issues/9).
- [x] Support OSX for Apple Darwin, macOS, [#11](https://github.com/ossrs/state-threads/issues/11).
- [x] Support sendmmsg for UDP, [#12](https://github.com/ossrs/state-threads/issues/12).
- [ ] Support sendmmsg for UDP, [#12](https://github.com/ossrs/state-threads/issues/12).
- [x] Refine performance for sleep or epoll_wait(0), [#17](https://github.com/ossrs/state-threads/issues/17).
- [ ] Improve the performance of timer. [9fe8cfe5b](https://github.com/ossrs/state-threads/commit/9fe8cfe5b1c9741a2e671a46215184f267fba400), [7879c2b](https://github.com/ossrs/state-threads/commit/7879c2b), [387cddb](https://github.com/ossrs/state-threads/commit/387cddb)
- [x] Support utest by gtest and coverage by gcov/gocvr.
- [ ] Support Multiple Threads for Linux and Darwin. [#19](https://github.com/ossrs/state-threads/issues/19), [srs#2188](https://github.com/ossrs/srs/issues/2188).
## GDB Tools

30
trunk/3rdparty/st-srs/auto/fast.sh vendored Executable file
View file

@ -0,0 +1,30 @@
#!/bin/bash
PWD=$(cd `dirname $0`/.. && pwd)
pushd $PWD
echo "Run UTest in $(pwd)"
IS_LINUX=yes
uname -s|grep Darwin >/dev/null && IS_DARWIN=yes && IS_LINUX=no
echo "IS_LINUX: $IS_LINUX, IS_DARWIN: $IS_DARWIN"
echo "Clean gcda files"
rm -f ./obj/*.gcda
echo "Build and run utest"
if [[ $IS_DARWIN == yes ]]; then
make darwin-debug-gcov && ./obj/st_utest
else
make linux-debug-gcov && ./obj/st_utest
fi
ret=$?; if [[ 0 -ne $ret ]]; then echo "Make ST utest fail, ret=$ret"; exit $ret; fi
echo "Generating coverage"
mkdir -p coverage &&
gcovr -r . -e LINUX -e DARWIN -e examples --html --html-details -o coverage/st.html &&
echo "Coverage report at coverage/st.html" &&
open coverage/st.html
popd
echo "UTest done, restore $(pwd)"

View file

@ -155,9 +155,6 @@ typedef struct _st_stack {
char *stk_bottom; /* Lowest address of stack's usable portion */
char *stk_top; /* Highest address of stack's usable portion */
void *sp; /* Stack pointer from C's point of view */
#ifdef __ia64__
void *bsp; /* Register stack backing store pointer */
#endif
/* merge from https://github.com/toffaletti/state-threads/commit/7f57fc9acc05e657bca1223f1e5b9b1a45ed929b */
#ifndef NVALGRIND
/* id returned by VALGRIND_STACK_REGISTER */
@ -368,11 +365,7 @@ extern _st_eventsys_t *_st_eventsys;
#define ST_UTIME_NO_TIMEOUT ((st_utime_t) -1LL)
#endif
#ifndef __ia64__
#define ST_DEFAULT_STACK_SIZE (64*1024)
#else
#define ST_DEFAULT_STACK_SIZE (128*1024) /* Includes register stack size */
#endif
#define ST_DEFAULT_STACK_SIZE (128*1024) /* Includes register stack size */
#ifndef ST_KEYS_MAX
#define ST_KEYS_MAX 16

View file

@ -55,40 +55,11 @@ unsigned long long _st_stat_epoll_shake = 0;
unsigned long long _st_stat_epoll_spin = 0;
#endif
#if defined(USE_POLL) && !defined(MD_HAVE_POLL)
/* Force poll usage if explicitly asked for it */
#define MD_HAVE_POLL
#if !defined(MD_HAVE_KQUEUE) && !defined(MD_HAVE_EPOLL)
#error Only support epoll(for Linux) or kqueue(for Darwin)
#endif
static struct _st_seldata {
fd_set fd_read_set, fd_write_set, fd_exception_set;
int fd_ref_cnts[FD_SETSIZE][3];
int maxfd;
} *_st_select_data;
#define _ST_SELECT_MAX_OSFD (_st_select_data->maxfd)
#define _ST_SELECT_READ_SET (_st_select_data->fd_read_set)
#define _ST_SELECT_WRITE_SET (_st_select_data->fd_write_set)
#define _ST_SELECT_EXCEP_SET (_st_select_data->fd_exception_set)
#define _ST_SELECT_READ_CNT(fd) (_st_select_data->fd_ref_cnts[fd][0])
#define _ST_SELECT_WRITE_CNT(fd) (_st_select_data->fd_ref_cnts[fd][1])
#define _ST_SELECT_EXCEP_CNT(fd) (_st_select_data->fd_ref_cnts[fd][2])
#ifdef MD_HAVE_POLL
static struct _st_polldata {
struct pollfd *pollfds;
int pollfds_size;
int fdcnt;
} *_st_poll_data;
#define _ST_POLL_OSFD_CNT (_st_poll_data->fdcnt)
#define _ST_POLLFDS (_st_poll_data->pollfds)
#define _ST_POLLFDS_SIZE (_st_poll_data->pollfds_size)
#endif /* MD_HAVE_POLL */
#ifdef MD_HAVE_KQUEUE
typedef struct _kq_fd_data {
int rd_ref_cnt;
@ -108,7 +79,6 @@ static struct _st_kqdata {
int dellist_size;
int dellist_cnt;
int kq;
pid_t pid;
} *_st_kq_data;
#ifndef ST_KQ_MIN_EVTLIST_SIZE
@ -137,7 +107,6 @@ static struct _st_epolldata {
int evtlist_cnt;
int fd_hint;
int epfd;
pid_t pid;
} *_st_epoll_data;
#ifndef ST_EPOLL_EVTLIST_SIZE
@ -161,451 +130,6 @@ static struct _st_epolldata {
_st_eventsys_t *_st_eventsys = NULL;
/*****************************************
* select event system
*/
ST_HIDDEN int _st_select_init(void)
{
_st_select_data = (struct _st_seldata *) malloc(sizeof(*_st_select_data));
if (!_st_select_data)
return -1;
memset(_st_select_data, 0, sizeof(*_st_select_data));
_st_select_data->maxfd = -1;
return 0;
}
ST_HIDDEN int _st_select_pollset_add(struct pollfd *pds, int npds)
{
struct pollfd *pd;
struct pollfd *epd = pds + npds;
/* Do checks up front */
for (pd = pds; pd < epd; pd++) {
if (pd->fd < 0 || pd->fd >= FD_SETSIZE || !pd->events ||
(pd->events & ~(POLLIN | POLLOUT | POLLPRI))) {
errno = EINVAL;
return -1;
}
}
for (pd = pds; pd < epd; pd++) {
if (pd->events & POLLIN) {
FD_SET(pd->fd, &_ST_SELECT_READ_SET);
_ST_SELECT_READ_CNT(pd->fd)++;
}
if (pd->events & POLLOUT) {
FD_SET(pd->fd, &_ST_SELECT_WRITE_SET);
_ST_SELECT_WRITE_CNT(pd->fd)++;
}
if (pd->events & POLLPRI) {
FD_SET(pd->fd, &_ST_SELECT_EXCEP_SET);
_ST_SELECT_EXCEP_CNT(pd->fd)++;
}
if (_ST_SELECT_MAX_OSFD < pd->fd)
_ST_SELECT_MAX_OSFD = pd->fd;
}
return 0;
}
ST_HIDDEN void _st_select_pollset_del(struct pollfd *pds, int npds)
{
struct pollfd *pd;
struct pollfd *epd = pds + npds;
for (pd = pds; pd < epd; pd++) {
if (pd->events & POLLIN) {
if (--_ST_SELECT_READ_CNT(pd->fd) == 0)
FD_CLR(pd->fd, &_ST_SELECT_READ_SET);
}
if (pd->events & POLLOUT) {
if (--_ST_SELECT_WRITE_CNT(pd->fd) == 0)
FD_CLR(pd->fd, &_ST_SELECT_WRITE_SET);
}
if (pd->events & POLLPRI) {
if (--_ST_SELECT_EXCEP_CNT(pd->fd) == 0)
FD_CLR(pd->fd, &_ST_SELECT_EXCEP_SET);
}
}
}
ST_HIDDEN void _st_select_find_bad_fd(void)
{
_st_clist_t *q;
_st_pollq_t *pq;
int notify;
struct pollfd *pds, *epds;
int pq_max_osfd, osfd;
short events;
_ST_SELECT_MAX_OSFD = -1;
for (q = _ST_IOQ.next; q != &_ST_IOQ; q = q->next) {
pq = _ST_POLLQUEUE_PTR(q);
notify = 0;
epds = pq->pds + pq->npds;
pq_max_osfd = -1;
for (pds = pq->pds; pds < epds; pds++) {
osfd = pds->fd;
pds->revents = 0;
if (pds->events == 0)
continue;
if (fcntl(osfd, F_GETFL, 0) < 0) {
pds->revents = POLLNVAL;
notify = 1;
}
if (osfd > pq_max_osfd) {
pq_max_osfd = osfd;
}
}
if (notify) {
ST_REMOVE_LINK(&pq->links);
pq->on_ioq = 0;
/*
* Decrement the count of descriptors for each descriptor/event
* because this I/O request is being removed from the ioq
*/
for (pds = pq->pds; pds < epds; pds++) {
osfd = pds->fd;
events = pds->events;
if (events & POLLIN) {
if (--_ST_SELECT_READ_CNT(osfd) == 0) {
FD_CLR(osfd, &_ST_SELECT_READ_SET);
}
}
if (events & POLLOUT) {
if (--_ST_SELECT_WRITE_CNT(osfd) == 0) {
FD_CLR(osfd, &_ST_SELECT_WRITE_SET);
}
}
if (events & POLLPRI) {
if (--_ST_SELECT_EXCEP_CNT(osfd) == 0) {
FD_CLR(osfd, &_ST_SELECT_EXCEP_SET);
}
}
}
if (pq->thread->flags & _ST_FL_ON_SLEEPQ)
_ST_DEL_SLEEPQ(pq->thread);
pq->thread->state = _ST_ST_RUNNABLE;
_ST_ADD_RUNQ(pq->thread);
} else {
if (_ST_SELECT_MAX_OSFD < pq_max_osfd)
_ST_SELECT_MAX_OSFD = pq_max_osfd;
}
}
}
ST_HIDDEN void _st_select_dispatch(void)
{
struct timeval timeout, *tvp;
fd_set r, w, e;
fd_set *rp, *wp, *ep;
int nfd, pq_max_osfd, osfd;
_st_clist_t *q;
st_utime_t min_timeout;
_st_pollq_t *pq;
int notify;
struct pollfd *pds, *epds;
short events, revents;
/*
* Assignment of fd_sets
*/
r = _ST_SELECT_READ_SET;
w = _ST_SELECT_WRITE_SET;
e = _ST_SELECT_EXCEP_SET;
rp = &r;
wp = &w;
ep = &e;
if (_ST_SLEEPQ == NULL) {
tvp = NULL;
} else {
min_timeout = (_ST_SLEEPQ->due <= _ST_LAST_CLOCK) ? 0 :
(_ST_SLEEPQ->due - _ST_LAST_CLOCK);
timeout.tv_sec = (int) (min_timeout / 1000000);
timeout.tv_usec = (int) (min_timeout % 1000000);
tvp = &timeout;
}
/* Check for I/O operations */
nfd = select(_ST_SELECT_MAX_OSFD + 1, rp, wp, ep, tvp);
/* Notify threads that are associated with the selected descriptors */
if (nfd > 0) {
_ST_SELECT_MAX_OSFD = -1;
for (q = _ST_IOQ.next; q != &_ST_IOQ; q = q->next) {
pq = _ST_POLLQUEUE_PTR(q);
notify = 0;
epds = pq->pds + pq->npds;
pq_max_osfd = -1;
for (pds = pq->pds; pds < epds; pds++) {
osfd = pds->fd;
events = pds->events;
revents = 0;
if ((events & POLLIN) && FD_ISSET(osfd, rp)) {
revents |= POLLIN;
}
if ((events & POLLOUT) && FD_ISSET(osfd, wp)) {
revents |= POLLOUT;
}
if ((events & POLLPRI) && FD_ISSET(osfd, ep)) {
revents |= POLLPRI;
}
pds->revents = revents;
if (revents) {
notify = 1;
}
if (osfd > pq_max_osfd) {
pq_max_osfd = osfd;
}
}
if (notify) {
ST_REMOVE_LINK(&pq->links);
pq->on_ioq = 0;
/*
* Decrement the count of descriptors for each descriptor/event
* because this I/O request is being removed from the ioq
*/
for (pds = pq->pds; pds < epds; pds++) {
osfd = pds->fd;
events = pds->events;
if (events & POLLIN) {
if (--_ST_SELECT_READ_CNT(osfd) == 0) {
FD_CLR(osfd, &_ST_SELECT_READ_SET);
}
}
if (events & POLLOUT) {
if (--_ST_SELECT_WRITE_CNT(osfd) == 0) {
FD_CLR(osfd, &_ST_SELECT_WRITE_SET);
}
}
if (events & POLLPRI) {
if (--_ST_SELECT_EXCEP_CNT(osfd) == 0) {
FD_CLR(osfd, &_ST_SELECT_EXCEP_SET);
}
}
}
if (pq->thread->flags & _ST_FL_ON_SLEEPQ)
_ST_DEL_SLEEPQ(pq->thread);
pq->thread->state = _ST_ST_RUNNABLE;
_ST_ADD_RUNQ(pq->thread);
} else {
if (_ST_SELECT_MAX_OSFD < pq_max_osfd)
_ST_SELECT_MAX_OSFD = pq_max_osfd;
}
}
} else if (nfd < 0) {
/*
* It can happen when a thread closes file descriptor
* that is being used by some other thread -- BAD!
*/
if (errno == EBADF)
_st_select_find_bad_fd();
}
}
ST_HIDDEN int _st_select_fd_new(int osfd)
{
if (osfd >= FD_SETSIZE) {
errno = EMFILE;
return -1;
}
return 0;
}
ST_HIDDEN int _st_select_fd_close(int osfd)
{
if (_ST_SELECT_READ_CNT(osfd) || _ST_SELECT_WRITE_CNT(osfd) ||
_ST_SELECT_EXCEP_CNT(osfd)) {
errno = EBUSY;
return -1;
}
return 0;
}
ST_HIDDEN int _st_select_fd_getlimit(void)
{
return FD_SETSIZE;
}
static _st_eventsys_t _st_select_eventsys = {
"select",
ST_EVENTSYS_SELECT,
_st_select_init,
_st_select_dispatch,
_st_select_pollset_add,
_st_select_pollset_del,
_st_select_fd_new,
_st_select_fd_close,
_st_select_fd_getlimit
};
#ifdef MD_HAVE_POLL
/*****************************************
* poll event system
*/
ST_HIDDEN int _st_poll_init(void)
{
_st_poll_data = (struct _st_polldata *) malloc(sizeof(*_st_poll_data));
if (!_st_poll_data)
return -1;
_ST_POLLFDS = (struct pollfd *) malloc(ST_MIN_POLLFDS_SIZE *
sizeof(struct pollfd));
if (!_ST_POLLFDS) {
free(_st_poll_data);
_st_poll_data = NULL;
return -1;
}
_ST_POLLFDS_SIZE = ST_MIN_POLLFDS_SIZE;
_ST_POLL_OSFD_CNT = 0;
return 0;
}
ST_HIDDEN int _st_poll_pollset_add(struct pollfd *pds, int npds)
{
struct pollfd *pd;
struct pollfd *epd = pds + npds;
for (pd = pds; pd < epd; pd++) {
if (pd->fd < 0 || !pd->events) {
errno = EINVAL;
return -1;
}
}
_ST_POLL_OSFD_CNT += npds;
return 0;
}
/* ARGSUSED */
ST_HIDDEN void _st_poll_pollset_del(struct pollfd *pds, int npds)
{
_ST_POLL_OSFD_CNT -= npds;
ST_ASSERT(_ST_POLL_OSFD_CNT >= 0);
}
ST_HIDDEN void _st_poll_dispatch(void)
{
int timeout, nfd;
_st_clist_t *q;
st_utime_t min_timeout;
_st_pollq_t *pq;
struct pollfd *pds, *epds, *pollfds;
/*
* Build up the array of struct pollfd to wait on.
* If existing array is not big enough, release it and allocate a new one.
*/
ST_ASSERT(_ST_POLL_OSFD_CNT >= 0);
if (_ST_POLL_OSFD_CNT > _ST_POLLFDS_SIZE) {
free(_ST_POLLFDS);
_ST_POLLFDS = (struct pollfd *) malloc((_ST_POLL_OSFD_CNT + 10) *
sizeof(struct pollfd));
ST_ASSERT(_ST_POLLFDS != NULL);
_ST_POLLFDS_SIZE = _ST_POLL_OSFD_CNT + 10;
}
pollfds = _ST_POLLFDS;
/* Gather all descriptors into one array */
for (q = _ST_IOQ.next; q != &_ST_IOQ; q = q->next) {
pq = _ST_POLLQUEUE_PTR(q);
memcpy(pollfds, pq->pds, sizeof(struct pollfd) * pq->npds);
pollfds += pq->npds;
}
ST_ASSERT(pollfds <= _ST_POLLFDS + _ST_POLLFDS_SIZE);
if (_ST_SLEEPQ == NULL) {
timeout = -1;
} else {
min_timeout = (_ST_SLEEPQ->due <= _ST_LAST_CLOCK) ? 0 :
(_ST_SLEEPQ->due - _ST_LAST_CLOCK);
timeout = (int) (min_timeout / 1000);
}
/* Check for I/O operations */
nfd = poll(_ST_POLLFDS, _ST_POLL_OSFD_CNT, timeout);
/* Notify threads that are associated with the selected descriptors */
if (nfd > 0) {
pollfds = _ST_POLLFDS;
for (q = _ST_IOQ.next; q != &_ST_IOQ; q = q->next) {
pq = _ST_POLLQUEUE_PTR(q);
epds = pollfds + pq->npds;
for (pds = pollfds; pds < epds; pds++) {
if (pds->revents)
break;
}
if (pds < epds) {
memcpy(pq->pds, pollfds, sizeof(struct pollfd) * pq->npds);
ST_REMOVE_LINK(&pq->links);
pq->on_ioq = 0;
if (pq->thread->flags & _ST_FL_ON_SLEEPQ)
_ST_DEL_SLEEPQ(pq->thread);
pq->thread->state = _ST_ST_RUNNABLE;
_ST_ADD_RUNQ(pq->thread);
_ST_POLL_OSFD_CNT -= pq->npds;
ST_ASSERT(_ST_POLL_OSFD_CNT >= 0);
}
pollfds = epds;
}
}
}
/* ARGSUSED */
ST_HIDDEN int _st_poll_fd_new(int osfd)
{
return 0;
}
/* ARGSUSED */
ST_HIDDEN int _st_poll_fd_close(int osfd)
{
/*
* We don't maintain I/O counts for poll event system
* so nothing to check here.
*/
return 0;
}
ST_HIDDEN int _st_poll_fd_getlimit(void)
{
/* zero means no specific limit */
return 0;
}
static _st_eventsys_t _st_poll_eventsys = {
"poll",
ST_EVENTSYS_POLL,
_st_poll_init,
_st_poll_dispatch,
_st_poll_pollset_add,
_st_poll_pollset_del,
_st_poll_fd_new,
_st_poll_fd_close,
_st_poll_fd_getlimit
};
#endif /* MD_HAVE_POLL */
#ifdef MD_HAVE_KQUEUE
/*****************************************
* kqueue event system
@ -626,7 +150,6 @@ ST_HIDDEN int _st_kq_init(void)
goto cleanup_kq;
}
fcntl(_st_kq_data->kq, F_SETFD, FD_CLOEXEC);
_st_kq_data->pid = getpid();
/*
* Allocate file descriptor data array.
@ -862,7 +385,6 @@ ST_HIDDEN void _st_kq_dispatch(void)
tsp = &timeout;
}
retry_kevent:
/* Check for I/O operations */
nfd = kevent(_st_kq_data->kq,
_st_kq_data->addlist, _st_kq_data->addlist_cnt,
@ -956,24 +478,6 @@ ST_HIDDEN void _st_kq_dispatch(void)
osfd = _st_kq_data->evtlist[i].ident;
_ST_KQ_REVENTS(osfd) = 0;
}
} else if (nfd < 0) {
if (errno == EBADF && _st_kq_data->pid != getpid()) {
/* We probably forked, reinitialize kqueue */
if ((_st_kq_data->kq = kqueue()) < 0) {
/* There is nothing we can do here, will retry later */
return;
}
fcntl(_st_kq_data->kq, F_SETFD, FD_CLOEXEC);
_st_kq_data->pid = getpid();
/* Re-register all descriptors on ioq with new kqueue */
memset(_st_kq_data->fd_data, 0, _st_kq_data->fd_data_size * sizeof(_kq_fd_data_t));
for (q = _ST_IOQ.next; q != &_ST_IOQ; q = q->next) {
pq = _ST_POLLQUEUE_PTR(q);
_st_kq_pollset_add(pq->pds, pq->npds);
}
goto retry_kevent;
}
}
}
@ -1039,7 +543,6 @@ ST_HIDDEN int _st_epoll_init(void)
goto cleanup_epoll;
}
fcntl(_st_epoll_data->epfd, F_SETFD, FD_CLOEXEC);
_st_epoll_data->pid = getpid();
/* Allocate file descriptor data array */
_st_epoll_data->fd_data_size = _st_epoll_data->fd_hint;
@ -1239,26 +742,6 @@ ST_HIDDEN void _st_epoll_dispatch(void)
}
}
if (_st_epoll_data->pid != getpid()) {
/* We probably forked, reinitialize epoll set */
close(_st_epoll_data->epfd);
_st_epoll_data->epfd = epoll_create(_st_epoll_data->fd_hint);
if (_st_epoll_data->epfd < 0) {
/* There is nothing we can do here, will retry later */
return;
}
fcntl(_st_epoll_data->epfd, F_SETFD, FD_CLOEXEC);
_st_epoll_data->pid = getpid();
/* Put all descriptors on ioq into new epoll set */
memset(_st_epoll_data->fd_data, 0, _st_epoll_data->fd_data_size * sizeof(_epoll_fd_data_t));
_st_epoll_data->evtlist_cnt = 0;
for (q = _ST_IOQ.next; q != &_ST_IOQ; q = q->next) {
pq = _ST_POLLQUEUE_PTR(q);
_st_epoll_pollset_add(pq->pds, pq->npds);
}
}
/* Check for I/O operations */
nfd = epoll_wait(_st_epoll_data->epfd, _st_epoll_data->evtlist, _st_epoll_data->evtlist_size, timeout);
@ -1402,36 +885,20 @@ int st_set_eventsys(int eventsys)
return -1;
}
switch (eventsys) {
case ST_EVENTSYS_DEFAULT:
#ifdef USE_POLL
_st_eventsys = &_st_poll_eventsys;
#else
_st_eventsys = &_st_select_eventsys;
#endif
break;
case ST_EVENTSYS_SELECT:
_st_eventsys = &_st_select_eventsys;
break;
#ifdef MD_HAVE_POLL
case ST_EVENTSYS_POLL:
_st_eventsys = &_st_poll_eventsys;
break;
#endif
case ST_EVENTSYS_ALT:
#if defined (MD_HAVE_KQUEUE)
_st_eventsys = &_st_kq_eventsys;
_st_eventsys = &_st_kq_eventsys;
return 0;
#elif defined (MD_HAVE_EPOLL)
if (_st_epoll_is_supported())
_st_eventsys = &_st_epoll_eventsys;
#endif
break;
default:
errno = EINVAL;
return -1;
if (_st_epoll_is_supported()) {
_st_eventsys = &_st_epoll_eventsys;
return 0;
}
return 0;
errno = EINVAL;
return -1;
#else
#error Only support epoll(for Linux) or kqueue(for Darwin)
#endif
}
int st_get_eventsys(void)

View file

@ -1,115 +0,0 @@
#
# Portions created by SGI are Copyright (C) 2000 Silicon Graphics, Inc.
# All Rights Reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 3. Neither the name of Silicon Graphics, Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
##########################
# Supported OSes:
#
# AIX
# FREEBSD
# HPUX
# HPUX_64
# IRIX
# IRIX_64
# LINUX
# LINUX_IA64
# NETBSD
# OPENBSD
# OSF1
# SOLARIS
# SOLARIS_64
##########################
CC = cc
SHELL = /bin/sh
ECHO = /bin/echo
DEPTH = ..
BUILD =
TARGETDIR =
DEFINES =
CFLAGS =
OTHER_FLAGS =
OBJDIR = $(DEPTH)/$(TARGETDIR)
INCDIR = $(DEPTH)/$(TARGETDIR)
LIBST = $(OBJDIR)/libst.a
HEADER = $(INCDIR)/st.h
LIBRESOLV =
EXTRALIBS =
ifeq ($(OS),)
EXAMPLES = unknown
else
EXAMPLES = $(OBJDIR)/lookupdns $(OBJDIR)/proxy $(OBJDIR)/server
endif
##########################
# Platform section.
#
ifeq (DARWIN, $(findstring DARWIN, $(OS)))
LIBRESOLV = -lresolv
endif
ifeq (LINUX, $(findstring LINUX, $(OS)))
LIBRESOLV = -lresolv
endif
ifeq (SOLARIS, $(findstring SOLARIS, $(OS)))
LIBRESOLV = -lresolv
EXTRALIBS = -lsocket -lnsl
endif
#
# End of platform section.
##########################
all: $(EXAMPLES)
$(OBJDIR)/lookupdns: lookupdns.c $(OBJDIR)/res.o $(LIBST) $(HEADER)
$(CC) $(CFLAGS) -I$(INCDIR) lookupdns.c $(OBJDIR)/res.o $(LIBST) $(LIBRESOLV) $(EXTRALIBS) -o $@
$(OBJDIR)/proxy: proxy.c $(LIBST) $(HEADER)
$(CC) $(CFLAGS) -I$(INCDIR) proxy.c $(LIBST) $(EXTRALIBS) -o $@
$(OBJDIR)/server: server.c $(OBJDIR)/error.o $(LIBST) $(HEADER)
$(CC) $(CFLAGS) -I$(INCDIR) server.c $(OBJDIR)/error.o $(LIBST) $(EXTRALIBS) -o $@
$(OBJDIR)/%.o: %.c
$(CC) $(CFLAGS) -I$(INCDIR) -c $< -o $@
.DEFAULT:
@cd $(DEPTH); $(MAKE) $@

View file

@ -1,98 +0,0 @@
Portions created by SGI are Copyright (C) 2000 Silicon Graphics, Inc.
All Rights Reserved.
This directory contains three example programs.
---------------------------------------------------------------------------
PROGRAM
lookupdns
FILES
lookupdns.c
res.c
USAGE
lookupdns <hostname1> [<hostname2>] ...
DESCRIPTION
This program performs asynchronous DNS host name resolution and reports
IP address for each <hostname> specified as a command line argument.
One ST thread is created for each host name. All threads do host name
resolution concurrently.
---------------------------------------------------------------------------
PROGRAM
proxy
FILES
proxy.c
USAGE
proxy -l <local_addr> -r <remote_addr> [-p <num_processes>] [-S]
-l <local_addr> bind to local address specified as [<host>]:<port>
-r <remote_addr> connect to remote address specified as <host>:<port>
-p <num_processes> create specified number of processes
-S serialize accept() calls from different processes
on the same listening socket (if needed).
DESCRIPTION
This program acts as a generic gateway. It listens for connections to a
local address. Upon accepting a client connection, it connects to the
specified remote address and then just pumps the data through without any
modification.
---------------------------------------------------------------------------
PROGRAM
server
FILES
server.c
error.c
USAGE
server -l <log_directory> [<options>]
-l <log_directory> open all log files in specified directory.
Possible options:
-b <host>:<port> bind to specified address (multiple addresses
are permitted)
-p <num_processes> create specified number of processes
-t <min_thr>:<max_thr> specify thread limits per listening socket
across all processes
-u <user> change server's user id to specified value
-q <backlog> set max length of pending connections queue
-a enable access logging
-i run in interactive mode (useful for debugging)
-S serialize accept() calls from different processes
on the same listening socket (if needed).
DESCRIPTION
This program is a general server example. It accepts a client connection
and outputs a short HTML page. It can be easily adapted to provide
other services.
---------------------------------------------------------------------------

View file

@ -1,168 +0,0 @@
/*
* Portions created by SGI are Copyright (C) 2000 Silicon Graphics, Inc.
* All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Silicon Graphics, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include "st.h"
/*
* Simple error reporting functions.
* Suggested in W. Richard Stevens' "Advanced Programming in UNIX
* Environment".
*/
#define MAXLINE 4096 /* max line length */
static void err_doit(int, int, const char *, va_list);
/*
* Nonfatal error related to a system call.
* Print a message and return.
*/
void err_sys_report(int fd, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
err_doit(fd, 1, fmt, ap);
va_end(ap);
}
/*
* Fatal error related to a system call.
* Print a message and terminate.
*/
void err_sys_quit(int fd, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
err_doit(fd, 1, fmt, ap);
va_end(ap);
exit(1);
}
/*
* Fatal error related to a system call.
* Print a message, dump core, and terminate.
*/
void err_sys_dump(int fd, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
err_doit(fd, 1, fmt, ap);
va_end(ap);
abort(); /* dump core and terminate */
exit(1); /* shouldn't get here */
}
/*
* Nonfatal error unrelated to a system call.
* Print a message and return.
*/
void err_report(int fd, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
err_doit(fd, 0, fmt, ap);
va_end(ap);
}
/*
* Fatal error unrelated to a system call.
* Print a message and terminate.
*/
void err_quit(int fd, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
err_doit(fd, 0, fmt, ap);
va_end(ap);
exit(1);
}
/*
* Return a pointer to a string containing current time.
*/
char *err_tstamp(void)
{
static char *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
static char str[32];
static time_t lastt = 0;
struct tm *tmp;
time_t currt = st_time();
if (currt == lastt)
return str;
tmp = localtime(&currt);
sprintf(str, "[%02d/%s/%d:%02d:%02d:%02d] ", tmp->tm_mday,
months[tmp->tm_mon], 1900 + tmp->tm_year, tmp->tm_hour,
tmp->tm_min, tmp->tm_sec);
lastt = currt;
return str;
}
/*
* Print a message and return to caller.
* Caller specifies "errnoflag".
*/
static void err_doit(int fd, int errnoflag, const char *fmt, va_list ap)
{
int errno_save;
char buf[MAXLINE];
errno_save = errno; /* value caller might want printed */
strcpy(buf, err_tstamp()); /* prepend a message with time stamp */
vsprintf(buf + strlen(buf), fmt, ap);
if (errnoflag)
sprintf(buf + strlen(buf), ": %s\n", strerror(errno_save));
else
strcat(buf, "\n");
write(fd, buf, strlen(buf));
errno = errno_save;
}

View file

@ -1,103 +0,0 @@
/*
* Portions created by SGI are Copyright (C) 2000 Silicon Graphics, Inc.
* All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Silicon Graphics, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include "st.h"
#if !defined(NETDB_INTERNAL) && defined(h_NETDB_INTERNAL)
#define NETDB_INTERNAL h_NETDB_INTERNAL
#endif
/* Resolution timeout (in microseconds) */
#define TIMEOUT (2*1000000LL)
/* External function defined in the res.c file */
int dns_getaddr(const char *host, struct in_addr *addr, st_utime_t timeout);
void *do_resolve(void *host)
{
struct in_addr addr;
/* Use dns_getaddr() instead of gethostbyname(3) to get IP address */
if (dns_getaddr(host, &addr, TIMEOUT) < 0) {
fprintf(stderr, "dns_getaddr: can't resolve %s: ", (char *)host);
if (h_errno == NETDB_INTERNAL)
perror("");
else
herror("");
} else
printf("%-40s %s\n", (char *)host, inet_ntoa(addr));
return NULL;
}
/*
* Asynchronous DNS host name resolution. This program creates one
* ST thread for each host name (specified as command line arguments).
* All threads do host name resolution concurrently.
*/
int main(int argc, char *argv[])
{
int i;
if (argc < 2) {
fprintf(stderr, "Usage: %s <hostname1> [<hostname2>] ...\n", argv[0]);
exit(1);
}
if (st_init() < 0) {
perror("st_init");
exit(1);
}
for (i = 1; i < argc; i++) {
/* Create a separate thread for each host name */
if (st_thread_create(do_resolve, argv[i], 0, 0) == NULL) {
perror("st_thread_create");
exit(1);
}
}
st_thread_exit(NULL);
/* NOTREACHED */
return 1;
}

View file

@ -1,541 +0,0 @@
/*
* Portions created by SGI are Copyright (C) 2000 Silicon Graphics, Inc.
* All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Silicon Graphics, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include "st.h"
#define IOBUFSIZE (16*1024)
#define IOV_LEN 256
#define IOV_COUNT (IOBUFSIZE / IOV_LEN)
#ifndef INADDR_NONE
#define INADDR_NONE 0xffffffff
#endif
static char *prog; /* Program name */
static struct sockaddr_in rmt_addr; /* Remote address */
static unsigned long testing;
#define TESTING_VERBOSE 0x1
#define TESTING_READV 0x2
#define TESTING_READ_RESID 0x4
#define TESTING_WRITEV 0x8
#define TESTING_WRITE_RESID 0x10
static void read_address(const char *str, struct sockaddr_in *sin);
static void start_daemon(void);
static int cpu_count(void);
static void set_concurrency(int nproc);
static void *handle_request(void *arg);
static void print_sys_error(const char *msg);
/*
* This program acts as a generic gateway. It listens for connections
* to a local address ('-l' option). Upon accepting a client connection,
* it connects to the specified remote address ('-r' option) and then
* just pumps the data through without any modification.
*/
int main(int argc, char *argv[])
{
extern char *optarg;
int opt, sock, n;
int laddr, raddr, num_procs, alt_ev, one_process;
int serialize_accept = 0;
struct sockaddr_in lcl_addr, cli_addr;
st_netfd_t cli_nfd, srv_nfd;
prog = argv[0];
num_procs = laddr = raddr = alt_ev = one_process = 0;
/* Parse arguments */
while((opt = getopt(argc, argv, "l:r:p:Saht:X")) != EOF) {
switch (opt) {
case 'a':
alt_ev = 1;
break;
case 'l':
read_address(optarg, &lcl_addr);
laddr = 1;
break;
case 'r':
read_address(optarg, &rmt_addr);
if (rmt_addr.sin_addr.s_addr == INADDR_ANY) {
fprintf(stderr, "%s: invalid remote address: %s\n", prog, optarg);
exit(1);
}
raddr = 1;
break;
case 'p':
num_procs = atoi(optarg);
if (num_procs < 1) {
fprintf(stderr, "%s: invalid number of processes: %s\n", prog, optarg);
exit(1);
}
break;
case 'S':
/*
* Serialization decision is tricky on some platforms. For example,
* Solaris 2.6 and above has kernel sockets implementation, so supposedly
* there is no need for serialization. The ST library may be compiled
* on one OS version, but used on another, so the need for serialization
* should be determined at run time by the application. Since it's just
* an example, the serialization decision is left up to user.
* Only on platforms where the serialization is never needed on any OS
* version st_netfd_serialize_accept() is a no-op.
*/
serialize_accept = 1;
break;
case 't':
testing = strtoul(optarg, NULL, 0);
break;
case 'X':
one_process = 1;
break;
case 'h':
case '?':
fprintf(stderr, "Usage: %s [options] -l <[host]:port> -r <host:port>\n",
prog);
fprintf(stderr, "options are:\n");
fprintf(stderr, " -p <num_processes> number of parallel processes\n");
fprintf(stderr, " -S serialize accepts\n");
fprintf(stderr, " -a use alternate event system\n");
#ifdef DEBUG
fprintf(stderr, " -t mask testing/debugging mode\n");
fprintf(stderr, " -X one process, don't daemonize\n");
#endif
exit(1);
}
}
if (!laddr) {
fprintf(stderr, "%s: local address required\n", prog);
exit(1);
}
if (!raddr) {
fprintf(stderr, "%s: remote address required\n", prog);
exit(1);
}
if (num_procs == 0)
num_procs = cpu_count();
fprintf(stderr, "%s: starting proxy daemon on %s:%d\n", prog,
inet_ntoa(lcl_addr.sin_addr), ntohs(lcl_addr.sin_port));
/* Start the daemon */
if (one_process)
num_procs = 1;
else
start_daemon();
if (alt_ev)
st_set_eventsys(ST_EVENTSYS_ALT);
/* Initialize the ST library */
if (st_init() < 0) {
print_sys_error("st_init");
exit(1);
}
/* Create and bind listening socket */
if ((sock = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
print_sys_error("socket");
exit(1);
}
n = 1;
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&n, sizeof(n)) < 0) {
print_sys_error("setsockopt");
exit(1);
}
if (bind(sock, (struct sockaddr *)&lcl_addr, sizeof(lcl_addr)) < 0) {
print_sys_error("bind");
exit(1);
}
listen(sock, 128);
if ((srv_nfd = st_netfd_open_socket(sock)) == NULL) {
print_sys_error("st_netfd_open");
exit(1);
}
/* See the comment regarding serialization decision above */
if (num_procs > 1 && serialize_accept && st_netfd_serialize_accept(srv_nfd)
< 0) {
print_sys_error("st_netfd_serialize_accept");
exit(1);
}
/* Start server processes */
if (!one_process)
set_concurrency(num_procs);
for ( ; ; ) {
n = sizeof(cli_addr);
cli_nfd = st_accept(srv_nfd, (struct sockaddr *)&cli_addr, &n,
ST_UTIME_NO_TIMEOUT);
if (cli_nfd == NULL) {
print_sys_error("st_accept");
exit(1);
}
if (st_thread_create(handle_request, cli_nfd, 0, 0) == NULL) {
print_sys_error("st_thread_create");
exit(1);
}
}
/* NOTREACHED */
return 1;
}
static void read_address(const char *str, struct sockaddr_in *sin)
{
char host[128], *p;
struct hostent *hp;
unsigned short port;
strcpy(host, str);
if ((p = strchr(host, ':')) == NULL) {
fprintf(stderr, "%s: invalid address: %s\n", prog, host);
exit(1);
}
*p++ = '\0';
port = (unsigned short) atoi(p);
if (port < 1) {
fprintf(stderr, "%s: invalid port: %s\n", prog, p);
exit(1);
}
memset(sin, 0, sizeof(struct sockaddr_in));
sin->sin_family = AF_INET;
sin->sin_port = htons(port);
if (host[0] == '\0') {
sin->sin_addr.s_addr = INADDR_ANY;
return;
}
sin->sin_addr.s_addr = inet_addr(host);
if (sin->sin_addr.s_addr == INADDR_NONE) {
/* not dotted-decimal */
if ((hp = gethostbyname(host)) == NULL) {
fprintf(stderr, "%s: can't resolve address: %s\n", prog, host);
exit(1);
}
memcpy(&sin->sin_addr, hp->h_addr, hp->h_length);
}
}
#ifdef DEBUG
static void show_iov(const struct iovec *iov, int niov)
{
int i;
size_t total;
printf("iov %p has %d entries:\n", iov, niov);
total = 0;
for (i = 0; i < niov; i++) {
printf("iov[%3d] iov_base=%p iov_len=0x%lx(%lu)\n",
i, iov[i].iov_base, (unsigned long) iov[i].iov_len,
(unsigned long) iov[i].iov_len);
total += iov[i].iov_len;
}
printf("total 0x%lx(%ld)\n", (unsigned long) total, (unsigned long) total);
}
/*
* This version is tricked out to test all the
* st_(read|write)v?(_resid)? variants. Use the non-DEBUG version for
* anything serious. st_(read|write) are all this function really
* needs.
*/
static int pass(st_netfd_t in, st_netfd_t out)
{
char buf[IOBUFSIZE];
struct iovec iov[IOV_COUNT];
int ioviter, nw, nr;
if (testing & TESTING_READV) {
for (ioviter = 0; ioviter < IOV_COUNT; ioviter++) {
iov[ioviter].iov_base = &buf[ioviter * IOV_LEN];
iov[ioviter].iov_len = IOV_LEN;
}
if (testing & TESTING_VERBOSE) {
printf("readv(%p)...\n", in);
show_iov(iov, IOV_COUNT);
}
if (testing & TESTING_READ_RESID) {
struct iovec *riov = iov;
int riov_cnt = IOV_COUNT;
if (st_readv_resid(in, &riov, &riov_cnt, ST_UTIME_NO_TIMEOUT) == 0) {
if (testing & TESTING_VERBOSE) {
printf("resid\n");
show_iov(riov, riov_cnt);
printf("full\n");
show_iov(iov, IOV_COUNT);
}
nr = 0;
for (ioviter = 0; ioviter < IOV_COUNT; ioviter++)
nr += iov[ioviter].iov_len;
nr = IOBUFSIZE - nr;
} else
nr = -1;
} else
nr = (int) st_readv(in, iov, IOV_COUNT, ST_UTIME_NO_TIMEOUT);
} else {
if (testing & TESTING_READ_RESID) {
size_t resid = IOBUFSIZE;
if (st_read_resid(in, buf, &resid, ST_UTIME_NO_TIMEOUT) == 0)
nr = IOBUFSIZE - resid;
else
nr = -1;
} else
nr = (int) st_read(in, buf, IOBUFSIZE, ST_UTIME_NO_TIMEOUT);
}
if (testing & TESTING_VERBOSE)
printf("got 0x%x(%d) E=%d\n", nr, nr, errno);
if (nr <= 0)
return 0;
if (testing & TESTING_WRITEV) {
for (nw = 0, ioviter = 0; nw < nr;
nw += iov[ioviter].iov_len, ioviter++) {
iov[ioviter].iov_base = &buf[nw];
iov[ioviter].iov_len = nr - nw;
if (iov[ioviter].iov_len > IOV_LEN)
iov[ioviter].iov_len = IOV_LEN;
}
if (testing & TESTING_VERBOSE) {
printf("writev(%p)...\n", out);
show_iov(iov, ioviter);
}
if (testing & TESTING_WRITE_RESID) {
struct iovec *riov = iov;
int riov_cnt = ioviter;
if (st_writev_resid(out, &riov, &riov_cnt, ST_UTIME_NO_TIMEOUT) == 0) {
if (testing & TESTING_VERBOSE) {
printf("resid\n");
show_iov(riov, riov_cnt);
printf("full\n");
show_iov(iov, ioviter);
}
nw = 0;
while (--ioviter >= 0)
nw += iov[ioviter].iov_len;
nw = nr - nw;
} else
nw = -1;
} else
nw = st_writev(out, iov, ioviter, ST_UTIME_NO_TIMEOUT);
} else {
if (testing & TESTING_WRITE_RESID) {
size_t resid = nr;
if (st_write_resid(out, buf, &resid, ST_UTIME_NO_TIMEOUT) == 0)
nw = nr - resid;
else
nw = -1;
} else
nw = st_write(out, buf, nr, ST_UTIME_NO_TIMEOUT);
}
if (testing & TESTING_VERBOSE)
printf("put 0x%x(%d) E=%d\n", nw, nw, errno);
if (nw != nr)
return 0;
return 1;
}
#else /* DEBUG */
/*
* This version is the simple one suitable for serious use.
*/
static int pass(st_netfd_t in, st_netfd_t out)
{
char buf[IOBUFSIZE];
int nw, nr;
nr = (int) st_read(in, buf, IOBUFSIZE, ST_UTIME_NO_TIMEOUT);
if (nr <= 0)
return 0;
nw = st_write(out, buf, nr, ST_UTIME_NO_TIMEOUT);
if (nw != nr)
return 0;
return 1;
}
#endif
static void *handle_request(void *arg)
{
struct pollfd pds[2];
st_netfd_t cli_nfd, rmt_nfd;
int sock;
cli_nfd = (st_netfd_t) arg;
pds[0].fd = st_netfd_fileno(cli_nfd);
pds[0].events = POLLIN;
/* Connect to remote host */
if ((sock = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
print_sys_error("socket");
goto done;
}
if ((rmt_nfd = st_netfd_open_socket(sock)) == NULL) {
print_sys_error("st_netfd_open_socket");
close(sock);
goto done;
}
if (st_connect(rmt_nfd, (struct sockaddr *)&rmt_addr,
sizeof(rmt_addr), ST_UTIME_NO_TIMEOUT) < 0) {
print_sys_error("st_connect");
st_netfd_close(rmt_nfd);
goto done;
}
pds[1].fd = sock;
pds[1].events = POLLIN;
/*
* Now just pump the data through.
* XXX This should use one thread for each direction for true full-duplex.
*/
for ( ; ; ) {
pds[0].revents = 0;
pds[1].revents = 0;
if (st_poll(pds, 2, ST_UTIME_NO_TIMEOUT) <= 0) {
print_sys_error("st_poll");
break;
}
if (pds[0].revents & POLLIN) {
if (!pass(cli_nfd, rmt_nfd))
break;
}
if (pds[1].revents & POLLIN) {
if (!pass(rmt_nfd, cli_nfd))
break;
}
}
st_netfd_close(rmt_nfd);
done:
st_netfd_close(cli_nfd);
return NULL;
}
static void start_daemon(void)
{
pid_t pid;
/* Start forking */
if ((pid = fork()) < 0) {
print_sys_error("fork");
exit(1);
}
if (pid > 0)
exit(0); /* parent */
/* First child process */
setsid(); /* become session leader */
if ((pid = fork()) < 0) {
print_sys_error("fork");
exit(1);
}
if (pid > 0) /* first child */
exit(0);
chdir("/");
umask(022);
}
/*
* Create separate processes ("virtual processors"). Since it's just an
* example, there is no watchdog - the parent just exits leaving children
* on their own.
*/
static void set_concurrency(int nproc)
{
pid_t pid;
int i;
if (nproc < 1)
nproc = 1;
for (i = 0; i < nproc; i++) {
if ((pid = fork()) < 0) {
print_sys_error("fork");
exit(1);
}
/* Child returns */
if (pid == 0)
return;
}
/* Parent just exits */
exit(0);
}
static int cpu_count(void)
{
int n;
#if defined (_SC_NPROCESSORS_ONLN)
n = (int) sysconf(_SC_NPROCESSORS_ONLN);
#elif defined (_SC_NPROC_ONLN)
n = (int) sysconf(_SC_NPROC_ONLN);
#elif defined (HPUX)
#include <sys/mpctl.h>
n = mpctl(MPC_GETNUMSPUS, 0, 0);
#else
n = -1;
errno = ENOSYS;
#endif
return n;
}
static void print_sys_error(const char *msg)
{
fprintf(stderr, "%s: %s: %s\n", prog, msg, strerror(errno));
}

View file

@ -1,305 +0,0 @@
/*
* Copyright (c) 1985, 1988, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* Portions created by SGI are Copyright (C) 2000 Silicon Graphics, Inc.
* All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Silicon Graphics, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#if defined (DARWIN)
#define BIND_8_COMPAT
#endif
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <resolv.h>
#include <netdb.h>
#include <errno.h>
#include "st.h"
#define MAXPACKET 1024
#if !defined(NETDB_INTERNAL) && defined(h_NETDB_INTERNAL)
#define NETDB_INTERNAL h_NETDB_INTERNAL
#endif
/* New in Solaris 7 */
#if !defined(_getshort) && defined(ns_get16)
#define _getshort(cp) ns_get16(cp)
#endif
typedef union {
HEADER hdr;
u_char buf[MAXPACKET];
} querybuf_t;
static int parse_answer(querybuf_t *ans, int len, struct in_addr *addr)
{
char buf[MAXPACKET];
HEADER *ahp;
u_char *cp, *eoa;
int type, n;
ahp = &ans->hdr;
eoa = ans->buf + len;
cp = ans->buf + sizeof(HEADER);
while (ahp->qdcount > 0) {
ahp->qdcount--;
cp += dn_skipname(cp, eoa) + QFIXEDSZ;
}
while (ahp->ancount > 0 && cp < eoa) {
ahp->ancount--;
if ((n = dn_expand(ans->buf, eoa, cp, buf, sizeof(buf))) < 0)
break;
cp += n;
type = _getshort(cp);
cp += 8;
n = _getshort(cp);
cp += 2;
if (type == T_CNAME) {
cp += n;
continue;
}
memcpy(addr, cp, n);
return 0;
}
h_errno = TRY_AGAIN;
return -1;
}
static int query_domain(st_netfd_t nfd, const char *name, struct in_addr *addr,
st_utime_t timeout)
{
querybuf_t qbuf;
u_char *buf = qbuf.buf;
HEADER *hp = &qbuf.hdr;
int blen = sizeof(qbuf);
int i, len, id;
for (i = 0; i < _res.nscount; i++) {
len = res_mkquery(QUERY, name, C_IN, T_A, NULL, 0, NULL, buf, blen);
if (len <= 0) {
h_errno = NO_RECOVERY;
return -1;
}
id = hp->id;
if (st_sendto(nfd, buf, len, (struct sockaddr *)&(_res.nsaddr_list[i]),
sizeof(struct sockaddr), timeout) != len) {
h_errno = NETDB_INTERNAL;
/* EINTR means interrupt by other thread, NOT by a caught signal */
if (errno == EINTR)
return -1;
continue;
}
/* Wait for reply */
do {
len = st_recvfrom(nfd, buf, blen, NULL, NULL, timeout);
if (len <= 0)
break;
} while (id != hp->id);
if (len < HFIXEDSZ) {
h_errno = NETDB_INTERNAL;
if (len >= 0)
errno = EMSGSIZE;
else if (errno == EINTR) /* see the comment above */
return -1;
continue;
}
hp->ancount = ntohs(hp->ancount);
hp->qdcount = ntohs(hp->qdcount);
if ((hp->rcode != NOERROR) || (hp->ancount == 0)) {
switch (hp->rcode) {
case NXDOMAIN:
h_errno = HOST_NOT_FOUND;
break;
case SERVFAIL:
h_errno = TRY_AGAIN;
break;
case NOERROR:
h_errno = NO_DATA;
break;
case FORMERR:
case NOTIMP:
case REFUSED:
default:
h_errno = NO_RECOVERY;
}
continue;
}
if (parse_answer(&qbuf, len, addr) == 0)
return 0;
}
return -1;
}
#define CLOSE_AND_RETURN(ret) \
{ \
n = errno; \
st_netfd_close(nfd); \
errno = n; \
return (ret); \
}
int dns_getaddr(const char *host, struct in_addr *addr, st_utime_t timeout)
{
char name[MAXDNAME], **domain;
const char *cp;
int s, n, maxlen, dots;
int trailing_dot, tried_as_is;
st_netfd_t nfd;
if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
h_errno = NETDB_INTERNAL;
return -1;
}
if (_res.options & RES_USEVC) {
h_errno = NETDB_INTERNAL;
errno = ENOSYS;
return -1;
}
if (!host || *host == '\0') {
h_errno = HOST_NOT_FOUND;
return -1;
}
/* Create UDP socket */
if ((s = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
h_errno = NETDB_INTERNAL;
return -1;
}
if ((nfd = st_netfd_open_socket(s)) == NULL) {
h_errno = NETDB_INTERNAL;
n = errno;
close(s);
errno = n;
return -1;
}
maxlen = sizeof(name) - 1;
n = 0;
dots = 0;
trailing_dot = 0;
tried_as_is = 0;
for (cp = host; *cp && n < maxlen; cp++) {
dots += (*cp == '.');
name[n++] = *cp;
}
if (name[n - 1] == '.')
trailing_dot = 1;
/*
* If there are dots in the name already, let's just give it a try
* 'as is'. The threshold can be set with the "ndots" option.
*/
if (dots >= _res.ndots) {
if (query_domain(nfd, host, addr, timeout) == 0)
CLOSE_AND_RETURN(0);
if (h_errno == NETDB_INTERNAL && errno == EINTR)
CLOSE_AND_RETURN(-1);
tried_as_is = 1;
}
/*
* We do at least one level of search if
* - there is no dot and RES_DEFNAME is set, or
* - there is at least one dot, there is no trailing dot,
* and RES_DNSRCH is set.
*/
if ((!dots && (_res.options & RES_DEFNAMES)) ||
(dots && !trailing_dot && (_res.options & RES_DNSRCH))) {
name[n++] = '.';
for (domain = _res.dnsrch; *domain; domain++) {
strncpy(name + n, *domain, maxlen - n);
if (query_domain(nfd, name, addr, timeout) == 0)
CLOSE_AND_RETURN(0);
if (h_errno == NETDB_INTERNAL && errno == EINTR)
CLOSE_AND_RETURN(-1);
if (!(_res.options & RES_DNSRCH))
break;
}
}
/*
* If we have not already tried the name "as is", do that now.
* note that we do this regardless of how many dots were in the
* name or whether it ends with a dot.
*/
if (!tried_as_is) {
if (query_domain(nfd, host, addr, timeout) == 0)
CLOSE_AND_RETURN(0);
}
CLOSE_AND_RETURN(-1);
}

File diff suppressed because it is too large Load diff

View file

@ -1,91 +0,0 @@
#
# Portions created by SGI are Copyright (C) 2000 Silicon Graphics, Inc.
# All Rights Reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 3. Neither the name of Silicon Graphics, Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
CC = cc
SHELL = /bin/sh
ECHO = /bin/echo
DEPTH = ..
BUILD =
TARGETDIR = obj
DEFINES =
OTHER_FLAGS =
CFLAGS =
OBJDIR = $(DEPTH)/$(TARGETDIR)
INCDIR = $(DEPTH)/$(TARGETDIR)
LIBRESOLV =
EXTRALIBS =
SLIBRARY = $(OBJDIR)/libstx.a
OBJS = $(OBJDIR)/dnscache.o $(OBJDIR)/dnsres.o $(OBJDIR)/lrucache.o
CFLAGS += -Wall -I$(INCDIR)
AR = ar
ARFLAGS = rv
RANLIB = ranlib
##########################
# Platform section.
#
ifeq (LINUX, $(findstring LINUX, $(OS)))
LIBRESOLV = -lresolv
endif
ifeq ($(OS), SOLARIS)
LIBRESOLV = -lresolv
EXTRALIBS = -lsocket -lnsl
endif
#
# End of platform section.
##########################
all: $(SLIBRARY)
$(SLIBRARY): $(OBJS)
$(AR) $(ARFLAGS) $@ $(OBJS)
$(RANLIB) $@
$(OBJDIR)/%.o: %.c stx.h common.h
$(CC) $(CFLAGS) -c $< -o $@
clean:
rm -rf $(OBJS) $(SLIBRARY)
#.DEFAULT:
# @cd $(DEPTH); $(MAKE) $@

View file

@ -1,42 +0,0 @@
This directory contains extensions to the core State Threads Library
that were contributed by users. All files hereunder are not part of the
State Threads Library itself. They are provided as-is, without warranty
or support, and under whatever license terms their authors provided. To
contribute your own extensions, just mail them to the project
administrators or to one of the project's mailing lists; see
state-threads.sourceforge.net. Please indicate the license terms under
which the project may distribute your contribution.
========================================================================
stx_fileio
----------
Contributed by Jeff <jlb-st@houseofdistraction.com>, 4 Nov 2002.
Provides non-blocking random access file reading capability for
programs using the State Threads library. There is one public function:
ssize_t stx_file_read(st_netfd_t fd, off_t offset,
void *buf, size_t nbytes, st_utime_t timeout);
The implementation is not optimal in that the data is copied at least once
more than should be necessary. Its usefulness is limited to cases where
random access to a file is required and where starvation of other threads
is unacceptable.
The particular application which motivated this implementation was a UDP
file transfer protocol. Because the OS does very little buffering of UDP
traffic it is important that UDP transmission threads are not starved for
periods of time which are long relative to the interval required to
maintain a steady send rate.
Licensed under the same dual MPL/GPL as core State Threads.
========================================================================
stx_dns
-------
Documentation coming.
========================================================================

View file

@ -1,77 +0,0 @@
#ifndef _STX_COMMON_H_
#define _STX_COMMON_H_
#include <stddef.h>
#include <stdlib.h>
#define STX_BEGIN_MACRO {
#define STX_END_MACRO }
/*****************************************
* Circular linked list definitions
*/
typedef struct _stx_clist {
struct _stx_clist *next;
struct _stx_clist *prev;
} stx_clist_t;
/* Insert element "_e" into the list, before "_l" */
#define STX_CLIST_INSERT_BEFORE(_e,_l) \
STX_BEGIN_MACRO \
(_e)->next = (_l); \
(_e)->prev = (_l)->prev; \
(_l)->prev->next = (_e); \
(_l)->prev = (_e); \
STX_END_MACRO
/* Insert element "_e" into the list, after "_l" */
#define STX_CLIST_INSERT_AFTER(_e,_l) \
STX_BEGIN_MACRO \
(_e)->next = (_l)->next; \
(_e)->prev = (_l); \
(_l)->next->prev = (_e); \
(_l)->next = (_e); \
STX_END_MACRO
/* Append an element "_e" to the end of the list "_l" */
#define STX_CLIST_APPEND_LINK(_e,_l) STX_CLIST_INSERT_BEFORE(_e,_l)
/* Remove the element "_e" from it's circular list */
#define STX_CLIST_REMOVE_LINK(_e) \
STX_BEGIN_MACRO \
(_e)->prev->next = (_e)->next; \
(_e)->next->prev = (_e)->prev; \
STX_END_MACRO
/* Return the head/tail of the list */
#define STX_CLIST_HEAD(_l) (_l)->next
#define STX_CLIST_TAIL(_l) (_l)->prev
/* Return non-zero if the given circular list "_l" is empty, */
/* zero if the circular list is not empty */
#define STX_CLIST_IS_EMPTY(_l) \
((_l)->next == (_l))
/* Initialize a circular list */
#define STX_CLIST_INIT_CLIST(_l) \
STX_BEGIN_MACRO \
(_l)->next = (_l); \
(_l)->prev = (_l); \
STX_END_MACRO
/*****************************************
* Useful macros
*/
#ifndef offsetof
#define offsetof(type, identifier) ((size_t)&(((type *)0)->identifier))
#endif
#define STX_MIN(a, b) (((a) < (b)) ? (a) : (b))
#endif /* !_STX_COMMON_H_ */

View file

@ -1,190 +0,0 @@
#include "stx.h"
#include "common.h"
/*****************************************
* Basic types definitions
*/
typedef struct _stx_dns_data {
struct in_addr *addrs;
int num_addrs;
int cur;
time_t expires;
} stx_dns_data_t;
#define MAX_HOST_ADDRS 1024
static struct in_addr addr_list[MAX_HOST_ADDRS];
stx_cache_t *_stx_dns_cache = NULL;
extern int _stx_dns_ttl;
extern int _stx_dns_getaddrlist(const char *hostname, struct in_addr *addrs,
int *num_addrs, st_utime_t timeout);
static unsigned long hash_hostname(const void *key)
{
const char *name = (const char *)key;
unsigned long hash = 0;
while (*name)
hash = (hash << 4) - hash + *name++; /* hash = hash * 15 + *name++ */
return hash;
}
static void cleanup_entry(void *key, void *data)
{
if (key)
free(key);
if (data) {
if (((stx_dns_data_t *)data)->addrs)
free(((stx_dns_data_t *)data)->addrs);
free(data);
}
}
static int lookup_entry(const char *host, struct in_addr *addrs,
int *num_addrs, int rotate)
{
stx_cache_entry_t *entry;
stx_dns_data_t *data;
int n;
entry = stx_cache_entry_lookup(_stx_dns_cache, host);
if (entry) {
data = (stx_dns_data_t *)stx_cache_entry_getdata(entry);
if (st_time() <= data->expires) {
if (*num_addrs == 1) {
if (rotate) {
*addrs = data->addrs[data->cur++];
if (data->cur >= data->num_addrs)
data->cur = 0;
} else {
*addrs = data->addrs[0];
}
} else {
n = STX_MIN(*num_addrs, data->num_addrs);
memcpy(addrs, data->addrs, n * sizeof(*addrs));
*num_addrs = n;
}
stx_cache_entry_release(_stx_dns_cache, entry);
return 1;
}
/*
* Cache entry expired: decrement its refcount and purge it from cache.
*/
stx_cache_entry_release(_stx_dns_cache, entry);
stx_cache_entry_delete(_stx_dns_cache, entry);
}
return 0;
}
static void insert_entry(const char *host, struct in_addr *addrs, int count)
{
stx_cache_entry_t *entry;
stx_dns_data_t *data;
char *key;
size_t n;
if (_stx_dns_ttl > 0) {
key = strdup(host);
data = (stx_dns_data_t *)malloc(sizeof(stx_dns_data_t));
n = count * sizeof(*addrs);
if (data) {
data->addrs = (struct in_addr *)malloc(n);
if (data->addrs)
memcpy(data->addrs, addrs, n);
data->num_addrs = count;
data->cur = 0;
data->expires = st_time() + _stx_dns_ttl;
}
entry = stx_cache_entry_create(key, data, strlen(host) + 1 +
sizeof(stx_dns_data_t) + n +
stx_cache_entry_sizeof());
if (key && data && data->addrs && entry &&
stx_cache_entry_insert(_stx_dns_cache, entry) == 0) {
stx_cache_entry_release(_stx_dns_cache, entry);
return;
}
if (entry)
stx_cache_entry_delete(_stx_dns_cache, entry);
else
cleanup_entry(key, data);
}
}
int _stx_dns_cache_getaddrlist(const char *hostname, struct in_addr *addrs,
int *num_addrs, st_utime_t timeout,
int rotate)
{
char host[128];
int n, count;
if (!_stx_dns_cache)
return _stx_dns_getaddrlist(hostname, addrs, num_addrs, timeout);
for (n = 0; n < sizeof(host) - 1 && hostname[n]; n++) {
host[n] = tolower(hostname[n]);
}
host[n] = '\0';
if (lookup_entry(host, addrs, num_addrs, rotate))
return 0;
count = MAX_HOST_ADDRS;
if (_stx_dns_getaddrlist(host, addr_list, &count, timeout) < 0)
return -1;
n = STX_MIN(*num_addrs, count);
memcpy(addrs, addr_list, n * sizeof(*addrs));
*num_addrs = n;
insert_entry(host, addr_list, count);
return 0;
}
int stx_dns_cache_init(size_t max_size, size_t max_bytes, size_t hash_size)
{
_stx_dns_cache = stx_cache_create(max_size, max_bytes, hash_size,
hash_hostname,
(long (*)(const void *, const void *))strcmp,
cleanup_entry);
if (!_stx_dns_cache)
return -1;
return 0;
}
void stx_dns_cache_getinfo(stx_cache_info_t *info)
{
if (_stx_dns_cache)
stx_cache_getinfo(_stx_dns_cache, info);
else
memset(info, 0, sizeof(stx_cache_info_t));
}
int stx_dns_getaddrlist(const char *hostname, struct in_addr *addrs,
int *num_addrs, st_utime_t timeout)
{
return _stx_dns_cache_getaddrlist(hostname, addrs, num_addrs, timeout, 0);
}
int stx_dns_getaddr(const char *hostname, struct in_addr *addr,
st_utime_t timeout)
{
int n = 1;
return _stx_dns_cache_getaddrlist(hostname, addr, &n, timeout, 1);
}

View file

@ -1,305 +0,0 @@
/*
* Copyright (c) 1985, 1988, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* Portions created by SGI are Copyright (C) 2000 Silicon Graphics, Inc.
* All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Silicon Graphics, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "stx.h"
#define MAXPACKET 1024
#if !defined(NETDB_INTERNAL) && defined(h_NETDB_INTERNAL)
#define NETDB_INTERNAL h_NETDB_INTERNAL
#endif
/* New in Solaris 7 */
#if !defined(_getshort) && defined(ns_get16)
#define _getshort(cp) ns_get16(cp)
#define _getlong(cp) ns_get32(cp)
#endif
typedef union {
HEADER hdr;
u_char buf[MAXPACKET];
} querybuf_t;
int _stx_dns_ttl;
static int parse_answer(querybuf_t *ans, int len, struct in_addr *addrs,
int *num_addrs)
{
char buf[MAXPACKET];
HEADER *ahp;
u_char *cp, *eoa;
int type, n, i;
ahp = &ans->hdr;
eoa = ans->buf + len;
cp = ans->buf + sizeof(HEADER);
h_errno = TRY_AGAIN;
_stx_dns_ttl = -1;
i = 0;
while (ahp->qdcount > 0) {
ahp->qdcount--;
cp += dn_skipname(cp, eoa) + QFIXEDSZ;
}
while (ahp->ancount > 0 && cp < eoa && i < *num_addrs) {
ahp->ancount--;
if ((n = dn_expand(ans->buf, eoa, cp, buf, sizeof(buf))) < 0)
return -1;
cp += n;
if (cp + 4 + 4 + 2 >= eoa)
return -1;
type = _getshort(cp);
cp += 4;
if (type == T_A)
_stx_dns_ttl = _getlong(cp);
cp += 4;
n = _getshort(cp);
cp += 2;
if (type == T_A) {
if (n > sizeof(*addrs) || cp + n > eoa)
return -1;
memcpy(&addrs[i++], cp, n);
}
cp += n;
}
*num_addrs = i;
return 0;
}
static int query_domain(st_netfd_t nfd, const char *name,
struct in_addr *addrs, int *num_addrs,
st_utime_t timeout)
{
querybuf_t qbuf;
u_char *buf = qbuf.buf;
HEADER *hp = &qbuf.hdr;
int blen = sizeof(qbuf);
int i, len, id;
for (i = 0; i < _res.nscount; i++) {
len = res_mkquery(QUERY, name, C_IN, T_A, NULL, 0, NULL, buf, blen);
if (len <= 0) {
h_errno = NO_RECOVERY;
return -1;
}
id = hp->id;
if (st_sendto(nfd, buf, len, (struct sockaddr *)&(_res.nsaddr_list[i]),
sizeof(struct sockaddr), timeout) != len) {
h_errno = NETDB_INTERNAL;
/* EINTR means interrupt by other thread, NOT by a caught signal */
if (errno == EINTR)
return -1;
continue;
}
/* Wait for reply */
do {
len = st_recvfrom(nfd, buf, blen, NULL, NULL, timeout);
if (len <= 0)
break;
} while (id != hp->id);
if (len < HFIXEDSZ) {
h_errno = NETDB_INTERNAL;
if (len >= 0)
errno = EMSGSIZE;
else if (errno == EINTR) /* see the comment above */
return -1;
continue;
}
hp->ancount = ntohs(hp->ancount);
hp->qdcount = ntohs(hp->qdcount);
if ((hp->rcode != NOERROR) || (hp->ancount == 0)) {
switch (hp->rcode) {
case NXDOMAIN:
h_errno = HOST_NOT_FOUND;
break;
case SERVFAIL:
h_errno = TRY_AGAIN;
break;
case NOERROR:
h_errno = NO_DATA;
break;
case FORMERR:
case NOTIMP:
case REFUSED:
default:
h_errno = NO_RECOVERY;
}
continue;
}
if (parse_answer(&qbuf, len, addrs, num_addrs) == 0)
return 0;
}
return -1;
}
#define CLOSE_AND_RETURN(ret) \
{ \
n = errno; \
st_netfd_close(nfd); \
errno = n; \
return (ret); \
}
int _stx_dns_getaddrlist(const char *host, struct in_addr *addrs,
int *num_addrs, st_utime_t timeout)
{
char name[MAXDNAME], **domain;
const char *cp;
int s, n, maxlen, dots;
int trailing_dot, tried_as_is;
st_netfd_t nfd;
if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
h_errno = NETDB_INTERNAL;
return -1;
}
if (_res.options & RES_USEVC) {
h_errno = NETDB_INTERNAL;
errno = ENOSYS;
return -1;
}
if (!host || *host == '\0') {
h_errno = HOST_NOT_FOUND;
return -1;
}
/* Create UDP socket */
if ((s = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
h_errno = NETDB_INTERNAL;
return -1;
}
if ((nfd = st_netfd_open_socket(s)) == NULL) {
h_errno = NETDB_INTERNAL;
n = errno;
close(s);
errno = n;
return -1;
}
maxlen = sizeof(name) - 1;
n = 0;
dots = 0;
trailing_dot = 0;
tried_as_is = 0;
for (cp = host; *cp && n < maxlen; cp++) {
dots += (*cp == '.');
name[n++] = *cp;
}
if (name[n - 1] == '.')
trailing_dot = 1;
/*
* If there are dots in the name already, let's just give it a try
* 'as is'. The threshold can be set with the "ndots" option.
*/
if (dots >= _res.ndots) {
if (query_domain(nfd, host, addrs, num_addrs, timeout) == 0)
CLOSE_AND_RETURN(0);
if (h_errno == NETDB_INTERNAL && errno == EINTR)
CLOSE_AND_RETURN(-1);
tried_as_is = 1;
}
/*
* We do at least one level of search if
* - there is no dot and RES_DEFNAME is set, or
* - there is at least one dot, there is no trailing dot,
* and RES_DNSRCH is set.
*/
if ((!dots && (_res.options & RES_DEFNAMES)) ||
(dots && !trailing_dot && (_res.options & RES_DNSRCH))) {
name[n++] = '.';
for (domain = _res.dnsrch; *domain; domain++) {
strncpy(name + n, *domain, maxlen - n);
if (query_domain(nfd, name, addrs, num_addrs, timeout) == 0)
CLOSE_AND_RETURN(0);
if (h_errno == NETDB_INTERNAL && errno == EINTR)
CLOSE_AND_RETURN(-1);
if (!(_res.options & RES_DNSRCH))
break;
}
}
/*
* If we have not already tried the name "as is", do that now.
* note that we do this regardless of how many dots were in the
* name or whether it ends with a dot.
*/
if (!tried_as_is) {
if (query_domain(nfd, host, addrs, num_addrs, timeout) == 0)
CLOSE_AND_RETURN(0);
}
CLOSE_AND_RETURN(-1);
}

View file

@ -1,343 +0,0 @@
#include "stx.h"
#include "common.h"
/*****************************************
* Basic types definitions
*/
struct _stx_centry {
void *key; /* key for doing lookups */
void *data; /* data in the cache */
size_t weight; /* "weight" of this entry */
struct _stx_centry *next; /* next entry */
struct _stx_centry **pthis;
stx_clist_t lru_link; /* for putting this entry on LRU list */
int ref_count; /* use count for this entry */
int delete_pending; /* pending delete flag */
};
struct _stx_cache {
size_t max_size; /* max size of cache */
size_t cur_size; /* current size of cache */
size_t max_weight; /* cache capacity */
size_t cur_weight; /* current total "weight" of all entries */
size_t hash_size; /* size of hash table */
stx_cache_entry_t **table; /* hash table for this cache */
stx_clist_t lru_list; /* least-recently-used list */
/* Cache stats */
unsigned long hits; /* num cache hits */
unsigned long lookups; /* num cache lookups */
unsigned long inserts; /* num inserts */
unsigned long deletes; /* num deletes */
/* Functions */
unsigned long (*key_hash_fn)(const void *);
long (*key_cmp_fn)(const void *, const void *);
void (*cleanup_fn)(void *, void *);
};
#define STX_CACHE_ENTRY_PTR(_qp) \
((stx_cache_entry_t *)((char *)(_qp) - offsetof(stx_cache_entry_t, lru_link)))
/*****************************************
* Cache methods
*/
stx_cache_t *stx_cache_create(size_t max_size, size_t max_weight,
size_t hash_size,
unsigned long (*key_hash_fn)(const void *key),
long (*key_cmp_fn)(const void *key1,
const void *key2),
void (*cleanup_fn)(void *key, void *data))
{
stx_cache_t *newcache;
newcache = (stx_cache_t *)calloc(1, sizeof(stx_cache_t));
if (newcache == NULL)
return NULL;
newcache->table = (stx_cache_entry_t **)calloc(hash_size,
sizeof(stx_cache_entry_t *));
if (newcache->table == NULL) {
free(newcache);
return NULL;
}
newcache->max_size = max_size;
newcache->max_weight = max_weight;
newcache->hash_size = hash_size;
STX_CLIST_INIT_CLIST(&(newcache->lru_list));
newcache->key_hash_fn = key_hash_fn;
newcache->key_cmp_fn = key_cmp_fn;
newcache->cleanup_fn = cleanup_fn;
return newcache;
}
void stx_cache_empty(stx_cache_t *cache)
{
size_t i;
stx_cache_entry_t *entry, *next_entry;
for (i = 0; i < cache->hash_size; i++) {
entry = cache->table[i];
while (entry) {
next_entry = entry->next;
stx_cache_entry_delete(cache, entry);
entry = next_entry;
}
}
}
void stx_cache_traverse(stx_cache_t *cache,
void (*callback)(void *key, void *data))
{
size_t i;
stx_cache_entry_t *entry;
for (i = 0; i < cache->hash_size; i++) {
for (entry = cache->table[i]; entry; entry = entry->next) {
if (!entry->delete_pending)
(*callback)(entry->key, entry->data);
}
}
}
void stx_cache_traverse_lru(stx_cache_t *cache,
void (*callback)(void *key, void *data),
unsigned int n)
{
stx_clist_t *q;
stx_cache_entry_t *entry;
for (q = STX_CLIST_HEAD(&cache->lru_list); q != &cache->lru_list && n;
q = q->next, n--) {
entry = STX_CACHE_ENTRY_PTR(q);
(*callback)(entry->key, entry->data);
}
}
void stx_cache_traverse_mru(stx_cache_t *cache,
void (*callback)(void *key, void *data),
unsigned int n)
{
stx_clist_t *q;
stx_cache_entry_t *entry;
for (q = STX_CLIST_TAIL(&cache->lru_list); q != &cache->lru_list && n;
q = q->prev, n--) {
entry = STX_CACHE_ENTRY_PTR(q);
(*callback)(entry->key, entry->data);
}
}
size_t stx_cache_getsize(stx_cache_t *cache)
{
return cache->cur_size;
}
size_t stx_cache_getweight(stx_cache_t *cache)
{
return cache->cur_weight;
}
void stx_cache_getinfo(stx_cache_t *cache, stx_cache_info_t *info)
{
info->max_size = cache->max_size;
info->max_weight = cache->max_weight;
info->hash_size = cache->hash_size;
info->cur_size = cache->cur_size;
info->cur_weight = cache->cur_weight;
info->hits = cache->hits;
info->lookups = cache->lookups;
info->inserts = cache->inserts;
info->deletes = cache->deletes;
}
/*****************************************
* Cache entry methods
*/
stx_cache_entry_t *stx_cache_entry_create(void *key, void *data,
size_t weight)
{
stx_cache_entry_t *newentry;
newentry = (stx_cache_entry_t *)calloc(1, sizeof(stx_cache_entry_t));
if (newentry == NULL)
return NULL;
newentry->key = key;
newentry->data = data;
newentry->weight = weight;
return newentry;
}
void stx_cache_entry_delete(stx_cache_t *cache, stx_cache_entry_t *entry)
{
entry->delete_pending = 1;
if (entry->ref_count > 0)
return;
if (entry->pthis) {
*entry->pthis = entry->next;
if (entry->next)
entry->next->pthis = entry->pthis;
cache->cur_size--;
cache->cur_weight -= entry->weight;
cache->deletes++;
STX_CLIST_REMOVE_LINK(&(entry->lru_link));
}
if (cache->cleanup_fn)
cache->cleanup_fn(entry->key, entry->data);
entry->pthis = NULL;
entry->key = NULL;
entry->data = NULL;
free(entry);
}
stx_cache_entry_t *stx_cache_entry_lookup(stx_cache_t *cache, const void *key)
{
unsigned long bucket;
stx_cache_entry_t *entry;
cache->lookups++;
bucket = cache->key_hash_fn(key) % cache->hash_size;
for (entry = cache->table[bucket]; entry; entry = entry->next) {
if (!entry->delete_pending && cache->key_cmp_fn(key, entry->key) == 0)
break;
}
if (entry) {
cache->hits++;
if (entry->ref_count == 0)
STX_CLIST_REMOVE_LINK(&(entry->lru_link));
entry->ref_count++;
}
return entry;
}
void stx_cache_entry_release(stx_cache_t *cache, stx_cache_entry_t *entry)
{
if (entry->ref_count == 0)
return;
entry->ref_count--;
if (entry->ref_count == 0) {
STX_CLIST_APPEND_LINK(&(entry->lru_link), &(cache->lru_list));
if (entry->delete_pending)
stx_cache_entry_delete(cache, entry);
}
}
int stx_cache_entry_insert(stx_cache_t *cache, stx_cache_entry_t *entry)
{
stx_cache_entry_t *old_entry;
unsigned long bucket;
/*
* If cache capacity is exceeded, try to remove LRU entries till there is
* enough room or LRU list is empty.
*/
while (cache->cur_weight + entry->weight > cache->max_weight) {
old_entry = stx_cache_entry_getlru(cache);
if (!old_entry) {
/* cache capacity is exceeded and all entries are in use */
return -1;
}
stx_cache_entry_delete(cache, old_entry);
}
/* If cache size is exceeded, remove LRU entry */
if (cache->cur_size >= cache->max_size) {
old_entry = stx_cache_entry_getlru(cache);
if (!old_entry) {
/* cache size is exceeded and all entries are in use */
return -1;
}
stx_cache_entry_delete(cache, old_entry);
}
/* Don't add duplicate entries in the cache */
bucket = cache->key_hash_fn(entry->key) % cache->hash_size;
for (old_entry = cache->table[bucket]; old_entry;
old_entry = old_entry->next) {
if (!old_entry->delete_pending &&
cache->key_cmp_fn(entry->key, old_entry->key) == 0)
break;
}
if (old_entry)
stx_cache_entry_delete(cache, old_entry);
/* Insert in the hash table */
entry->next = cache->table[bucket];
cache->table[bucket] = entry;
entry->pthis = &cache->table[bucket];
if (entry->next)
entry->next->pthis = &entry->next;
entry->ref_count++;
cache->inserts++;
cache->cur_size++;
cache->cur_weight += entry->weight;
return 0;
}
stx_cache_entry_t *stx_cache_entry_getlru(stx_cache_t *cache)
{
if (STX_CLIST_IS_EMPTY(&(cache->lru_list)))
return NULL;
return STX_CACHE_ENTRY_PTR(STX_CLIST_HEAD(&(cache->lru_list)));
}
int stx_cache_entry_sizeof(void)
{
return (int)sizeof(stx_cache_entry_t);
}
void *stx_cache_entry_getdata(stx_cache_entry_t *entry)
{
return entry->data;
}
void *stx_cache_entry_getkey(stx_cache_entry_t *entry)
{
return entry->key;
}
size_t stx_cache_entry_getweight(stx_cache_entry_t *entry)
{
return entry->weight;
}

View file

@ -1,367 +0,0 @@
Michael Abd-El-Malek contributed this patch. He wrote:
----------------------------------------
Hello,
This is a patch that enables programmatically dumping the stack of
every thread. This has been useful in debugging deadlocks, etc...
Our usage model is that the SIGUSR2 handler calls the new
_st_print_thread_stacks function, which dumps the stack for all
threads. A convenient feature is that for thread stacks that are the
same (which is common for application with a lot of worker threads
waiting for work), only one stack trace is printed, along with a
count of how many threads have that same stack.
I use the glibc backtrace function to get the backtrace, and then use
popen to execute addr2line and convert memory addresses to file
names, function names, and line numbers. If glibc isn't available,
_st_print_thread_stacks just prints a warning. And this feature is
only available if DEBUG is turned on.
We've found this feature extremely helpful when debugging.
The patch can be a bit more robust (it assumes addr2line exists).
But I didn't want to go through the hassle of doing this, if the
StateThreads community doesn't want to use this patch. (In our
environment, addr2line will always be there.)
Cheers,
Mike
----------------------------------------
Invoking complex functions from a signal handler is not recommended,
plus this patch changes the behavior of existing API hooks. It will
not become part of State Threads proper but you may find it useful
nonetheless. This patch applies to st-1.5.2.
diff -Nur Makefile.1.5.2 Makefile
--- Makefile.1.5.2 Wed Sep 7 14:19:50 2005
+++ Makefile Wed Sep 7 14:33:08 2005
@@ -255,7 +255,8 @@
$(TARGETDIR)/stk.o \
$(TARGETDIR)/sync.o \
$(TARGETDIR)/key.o \
- $(TARGETDIR)/io.o
+ $(TARGETDIR)/io.o \
+ $(TARGETDIR)/backtrace.o
OBJS += $(EXTRA_OBJS)
HEADER = $(TARGETDIR)/st.h
SLIBRARY = $(TARGETDIR)/libst.a
diff -Nur backtrace.c.1.5.2 backtrace.c
--- backtrace.c.1.5.2 Wed Dec 31 16:00:00 1969
+++ backtrace.c Wed Sep 7 13:40:21 2005
@@ -0,0 +1,211 @@
+/*
+ * The contents of this file are subject to the Mozilla Public
+ * License Version 1.1 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * rights and limitations under the License.
+ *
+ * Contributor(s): Michael Abd-El-Malek (mabdelmalek@cmu.edu)
+ * Carnegie Mellon University
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License Version 2 or later (the
+ * "GPL"), in which case the provisions of the GPL are applicable
+ * instead of those above. If you wish to allow use of your
+ * version of this file only under the terms of the GPL and not to
+ * allow others to use your version of this file under the MPL,
+ * indicate your decision by deleting the provisions above and
+ * replace them with the notice and other provisions required by
+ * the GPL. If you do not delete the provisions above, a recipient
+ * may use your version of this file under either the MPL or the
+ * GPL.
+ */
+
+
+
+/*
+ * This file contains routines for printing a stack trace of all threads.
+ * Only works when DEBUG is defined and where glibc is available, since it
+ * provides the backtrace() function.
+ */
+
+#define _GNU_SOURCE /* to get program_invocation_name */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+
+#if defined(DEBUG) && defined(__GLIBC__)
+
+#include <errno.h>
+#include "common.h"
+#include <execinfo.h>
+#include <inttypes.h>
+#include <string.h>
+
+
+/* The maximum number of frames to get a stack trace for. If a thread has more
+ * frames than this, then we only show the latest X frames. */
+#define MAX_NUM_FRAMES 64
+
+
+typedef struct thread_stack_s {
+ uint32_t num_frames;
+ void* addresses[MAX_NUM_FRAMES]; /* frame pointers */
+ char* locations[MAX_NUM_FRAMES]; /* file/function/line numbers */
+ uint32_t num_matches;
+
+ struct thread_stack_s* next;
+} thread_stack_t;
+
+static thread_stack_t* stacks = NULL;
+
+
+/* Converts the function's memory addresses to function names, file names, and
+ * line numbers. Calls binutil's addr2line program. */
+static void get_symbol_names(thread_stack_t *stack)
+{
+ char program_to_run[1024], function[256], filename_lineno[256], temp[19];
+ FILE* output;
+ int num_bytes_left;
+ uint32_t i;
+
+ /* Construct the arguments to addr2line */
+ num_bytes_left = sizeof(program_to_run);
+ num_bytes_left -= snprintf(program_to_run, sizeof(program_to_run),
+ "addr2line -fCe %s", program_invocation_name);
+ for (i = 0; i < stack->num_frames && num_bytes_left > 0; ++i) {
+ num_bytes_left -= snprintf(temp, sizeof(temp), " %p", stack->addresses[i]);
+ strncat(program_to_run, temp, num_bytes_left);
+ }
+
+ /* Use popen to execute addr2line and read its ouput */
+ output = popen(program_to_run, "r");
+ for (i = 0; i < stack->num_frames; ++i) {
+ char* function_listing = (char*) malloc(512);
+ fscanf(output, "%255s\n", function);
+ fscanf(output, "%255s\n", filename_lineno);
+ snprintf(function_listing, 512, "%s at %s", function, filename_lineno);
+ stack->locations[i] = function_listing;
+ }
+ pclose(output);
+}
+
+
+static void print_stack(thread_stack_t* stack)
+{
+ int skip_offset = 0, cmp_len;
+ uint32_t i;
+
+ /* Get the function names/filenames/line numbers */
+ get_symbol_names(stack);
+
+ cmp_len = strlen("_st_iterate_threads_helper");
+
+ /* Print the backtrace */
+ for (i = 0; i < stack->num_frames; ++i) {
+ /* Skip frames we don't have location info for */
+ if (!strncmp(stack->locations[i], "??", 2)) {
+ continue;
+ }
+
+ /* Skip the frames that are used for printing the stack trace */
+ if (skip_offset) {
+ printf("\t#%2d %s %p\n", i - skip_offset, stack->locations[i],
+ stack->addresses[i]);
+ } else if (!strncmp(stack->locations[i], "_st_iterate_threads_helper",
+ cmp_len)) {
+ skip_offset = i + 1;
+ }
+ }
+}
+
+
+static void add_current_thread_stack(void)
+{
+ thread_stack_t *new_stack = malloc(sizeof(thread_stack_t));
+ thread_stack_t *search;
+
+ /* Call glibc function to get the backtrace */
+ new_stack->num_frames = backtrace(new_stack->addresses, MAX_NUM_FRAMES);
+
+ /* Check if we have another stacks that is equivalent. If so, then coaelsce
+ * two stacks into one, to minimize output to user. */
+ search = stacks;
+ while (search) {
+ if (search->num_frames == new_stack->num_frames &&
+ !memcmp(search->addresses, new_stack->addresses,
+ search->num_frames * sizeof(void*))) {
+ /* Found an existing stack that is the same as this thread's stack */
+ ++search->num_matches;
+ free(new_stack);
+ return;
+ } else {
+ search = search->next;
+ }
+ }
+
+ /* This is a new stack. Add it to the list of stacks. */
+ new_stack->num_matches = 1;
+ new_stack->next = stacks;
+ stacks = new_stack;
+}
+
+static void print_stack_frames(void)
+{
+ while (stacks) {
+ printf("\n%u thread(s) with this backtrace:\n", stacks->num_matches);
+ print_stack(stacks);
+ stacks = stacks->next;
+ }
+ printf("\n");
+}
+
+static void free_stacks(void)
+{
+ uint32_t i;
+ while (stacks) {
+ thread_stack_t *next = stacks->next;
+ for (i = 0; i < stacks->num_frames; ++i) {
+ free(stacks->locations[i]);
+ }
+ free(stacks);
+ stacks = next;
+ }
+ stacks = NULL;
+}
+
+
+static void st_print_thread_stack(_st_thread_t *thread, int start_flag,
+ int end_flag)
+{
+ if (end_flag == 0) {
+ add_current_thread_stack();
+ } else {
+ print_stack_frames();
+ }
+}
+
+
+void _st_print_thread_stacks(int ignore)
+{
+ _st_iterate_threads_flag = 1;
+ _st_iterate_threads_helper(st_print_thread_stack);
+ _st_iterate_threads_flag = 0;
+
+ /* Deallocate memory */
+ free_stacks();
+}
+
+#else /* defined(DEBUG) && defined(__GLIBC__) */
+
+void _st_print_thread_stacks(int ignore)
+{
+ printf("%s: need DEBUG mode and glibc-specific functions to read stack.\n",
+ __FUNCTION__);
+}
+#endif /* defined(DEBUG) && defined(__GLIBC__) */
diff -Nur common.h.1.5.2 common.h
--- common.h.1.5.2 Wed Sep 7 14:18:37 2005
+++ common.h Wed Sep 7 14:35:36 2005
@@ -371,8 +371,18 @@
*/
#ifdef DEBUG
-void _st_iterate_threads(void);
-#define ST_DEBUG_ITERATE_THREADS() _st_iterate_threads()
+typedef void(*_st_func_ptr_t)(_st_thread_t *thread,
+ int start_flag,
+ int end_flag);
+/* Pointer to function that will be called on thread switch */
+extern _st_func_ptr_t _st_iterate_func_ptr;
+extern int _st_iterate_threads_flag;
+/* Thread iteration function that will call an arbitrary function */
+extern void _st_iterate_threads_helper(_st_func_ptr_t func);
+#define ST_DEBUG_ITERATE_THREADS() \
+ if (_st_iterate_func_ptr) { \
+ _st_iterate_threads_helper(_st_iterate_func_ptr); \
+ }
#else
#define ST_DEBUG_ITERATE_THREADS()
#endif
diff -Nur public.h.1.5.2 public.h
--- public.h.1.5.2 Wed Sep 7 11:46:58 2005
+++ public.h Wed Sep 7 13:38:46 2005
@@ -171,8 +171,10 @@
extern st_netfd_t st_open(const char *path, int oflags, mode_t mode);
#ifdef DEBUG
-extern void _st_show_thread_stack(st_thread_t thread, const char *messg);
+extern void _st_show_thread_stack(st_thread_t thread, int start_flag,
+ int end_flag);
extern void _st_iterate_threads(void);
+extern void _st_print_thread_stacks(int ignore);
#endif
#ifdef __cplusplus
diff -Nur sched.c.1.5.2 sched.c
--- sched.c.1.5.2 Wed Sep 7 10:48:05 2005
+++ sched.c Wed Sep 7 13:38:46 2005
@@ -919,16 +919,13 @@
#ifdef DEBUG
-/* ARGSUSED */
-void _st_show_thread_stack(_st_thread_t *thread, const char *messg)
-{
-
-}
-
/* To be set from debugger */
int _st_iterate_threads_flag = 0;
+/* Thread iteration function that will call an arbitrary function */
+_st_func_ptr_t _st_iterate_func_ptr = NULL;
-void _st_iterate_threads(void)
+/* This function iterates over all threads, calling "func" for each thread. */
+void _st_iterate_threads_helper(_st_func_ptr_t func)
{
static _st_thread_t *thread = NULL;
static jmp_buf orig_jb, save_jb;
@@ -944,16 +941,20 @@
if (thread) {
memcpy(thread->context, save_jb, sizeof(jmp_buf));
- _st_show_thread_stack(thread, NULL);
+ func(thread, 0, 0);
} else {
if (MD_SETJMP(orig_jb)) {
_st_iterate_threads_flag = 0;
+ _st_iterate_func_ptr = NULL;
thread = NULL;
- _st_show_thread_stack(thread, "Iteration completed");
+ /* Last thread to iterate through */
+ func(thread, 0, 1);
return;
}
+ /* First thread to iterate through */
thread = _ST_CURRENT_THREAD();
- _st_show_thread_stack(thread, "Iteration started");
+ _st_iterate_func_ptr = func;
+ func(thread, 1, 0);
}
q = thread->tlink.next;
@@ -966,5 +967,17 @@
memcpy(save_jb, thread->context, sizeof(jmp_buf));
MD_LONGJMP(thread->context, 1);
}
+
+/* ARGSUSED */
+void _st_show_thread_stack(_st_thread_t *thread, int start_flag, int end_flag)
+{
+}
+
+/* Iterate over threads inside debugger; see st/README */
+void _st_iterate_threads(void)
+{
+ _st_iterate_threads_helper(_st_show_thread_stack);
+}
+
#endif /* DEBUG */

View file

@ -1,91 +0,0 @@
#ifndef _STX_H_
#define _STX_H_
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <resolv.h>
#include <netdb.h>
#include <errno.h>
#include "st.h"
#ifdef __cplusplus
extern "C" {
#endif
/*****************************************
* Basic types definitions
*/
typedef struct _stx_centry stx_cache_entry_t;
typedef struct _stx_cache stx_cache_t;
/* This is public type */
typedef struct _stx_cache_info {
size_t max_size;
size_t max_weight;
size_t hash_size;
size_t cur_size;
size_t cur_weight;
unsigned long hits;
unsigned long lookups;
unsigned long inserts;
unsigned long deletes;
} stx_cache_info_t;
/*****************************************
* Cache and cache entry methods
*/
stx_cache_t *stx_cache_create(size_t max_size, size_t max_weight,
size_t hash_size,
unsigned long (*key_hash_fn)(const void *key),
long (*key_cmp_fn)(const void *key1,
const void *key2),
void (*cleanup_fn)(void *key, void *data));
void stx_cache_empty(stx_cache_t *cache);
void stx_cache_traverse(stx_cache_t *cache,
void (*callback)(void *key, void *data));
void stx_cache_traverse_lru(stx_cache_t *, void (*)(void *, void *),
unsigned int);
void stx_cache_traverse_mru(stx_cache_t *, void (*)(void *, void *),
unsigned int);
void stx_cache_getinfo(stx_cache_t *cache, stx_cache_info_t *info);
size_t stx_cache_getsize(stx_cache_t *cache);
size_t stx_cache_getweight(stx_cache_t *cache);
stx_cache_entry_t *stx_cache_entry_create(void *key, void *data,
size_t weight);
void stx_cache_entry_delete(stx_cache_t *cache, stx_cache_entry_t *entry);
stx_cache_entry_t *stx_cache_entry_lookup(stx_cache_t *cache, const void *key);
void stx_cache_entry_release(stx_cache_t *, stx_cache_entry_t *);
int stx_cache_entry_insert(stx_cache_t *cache, stx_cache_entry_t *entry);
stx_cache_entry_t *stx_cache_entry_getlru(stx_cache_t *cache);
int stx_cache_entry_sizeof(void);
void *stx_cache_entry_getdata(stx_cache_entry_t *entry);
void *stx_cache_entry_getkey(stx_cache_entry_t *entry);
size_t stx_cache_entry_getweight(stx_cache_entry_t *entry);
int stx_dns_cache_init(size_t max_size, size_t max_bytes, size_t hash_size);
void stx_dns_cache_getinfo(stx_cache_info_t *info);
int stx_dns_getaddrlist(const char *hostname, struct in_addr *addrs,
int *num_addrs, st_utime_t timeout);
int stx_dns_getaddr(const char *hostname, struct in_addr *addr,
st_utime_t timeout);
#ifdef __cplusplus
}
#endif
#endif /* !_STX_H_ */

View file

@ -1,197 +0,0 @@
/*
* File I/O extension to the State Threads Library.
*/
/*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is the file I/O extension to the State Threads Library.
*
* The Initial Developer of the Original Code is Jeff
* <jlb-st@houseofdistraction.com>. Portions created by the Initial
* Developer are Copyright (C) 2002 the Initial Developer. All Rights
* Reserved.
*
* Contributor(s): (none)
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU General Public License Version 2 or later (the
* "GPL"), in which case the provisions of the GPL are applicable
* instead of those above. If you wish to allow use of your
* version of this file only under the terms of the GPL and not to
* allow others to use your version of this file under the MPL,
* indicate your decision by deleting the provisions above and
* replace them with the notice and other provisions required by
* the GPL. If you do not delete the provisions above, a recipient
* may use your version of this file under either the MPL or the
* GPL.
*/
#include <stdlib.h>
#include "stx_fileio.h"
#define STX_FILEIO_SIGNUM SIGUSR2
typedef struct {
st_netfd_t data_fd;
st_netfd_t control_fd;
pid_t pid;
} fileio_data_t;
#define FILEREADER_MAX_READ 1024
typedef struct {
off_t offset;
ssize_t nbytes;
} file_reader_cb_t;
/**
* Fork a process to read a file and return its pid. Receives
* offset/length commands from control stream and sends corresponding data
* to out stream. A zero length on the control stream signals an end.
*
* @param fd stream from which to read
* @param control_out receives the file descriptor to which control commands can be sent
* @param fd_out receives the file descriptor from which the output of the command can be read.
* @return PID of the process created to execute the command
*/
pid_t
file_reader(int fd, int *fd_control, int *fd_out)
{
pid_t pid;
int control_pipe[2], out_pipe[2];
if (pipe(control_pipe) < 0 || pipe(out_pipe) < 0)
return (pid_t)-1;
pid = fork();
if (pid == (pid_t) -1)
{
close(control_pipe[0]);
close(control_pipe[1]);
close(out_pipe[0]);
close(out_pipe[1]);
return pid;
}
else if (pid == (pid_t) 0)
{
// child
off_t pos = 0;
file_reader_cb_t cb;
char buf[FILEREADER_MAX_READ];
if (fd == -1)
_exit(EXIT_FAILURE);
while (sizeof(cb) == read(control_pipe[0], &cb, sizeof(cb))) {
ssize_t nb;
if (0 >= cb.nbytes)
goto clean_exit;
if (pos != cb.offset) {
pos = lseek(fd, cb.offset, SEEK_SET);
if (pos == (off_t)-1)
break;
}
nb = read(fd, buf, cb.nbytes);
if (nb == (ssize_t)-1)
break;
pos += nb;
write(out_pipe[1], (char *)&nb, sizeof(nb));
write(out_pipe[1], buf, nb);
}
perror("ERROR: file_reader: ");
clean_exit:
close(control_pipe[0]);
close(control_pipe[1]);
close(out_pipe[0]);
close(out_pipe[1]);
_exit(EXIT_SUCCESS);
}
// parent
close(out_pipe[1]);
close(control_pipe[0]);
*fd_out = out_pipe[0];
*fd_control = control_pipe[1];
return pid;
}
/**
* fileio_data_t destructor callback
*/
static void
fileio_data_destructor(void *dat_in)
{
if (dat_in) {
fileio_data_t *dat = (fileio_data_t *)dat_in;
file_reader_cb_t cb;
cb.offset = 0;
cb.nbytes = 0;
st_write(dat->control_fd, (char *)&cb, sizeof(cb),
ST_UTIME_NO_TIMEOUT);
waitpid(dat->pid, NULL, 0);
st_netfd_close(dat->control_fd);
st_netfd_close(dat->data_fd);
free(dat_in);
}
}
/**
* Retrieve fileio_data_t struct from an st descriptor. Create and store
* a new one if needed.
*/
static fileio_data_t *get_fileio_data(st_netfd_t fd)
{
fileio_data_t *dat = (fileio_data_t *)st_netfd_getspecific(fd);
if (!dat) {
int fd_control, fd_out;
pid_t pid = file_reader(st_netfd_fileno(fd), &fd_control, &fd_out);
if (pid != (pid_t)-1) {
dat = (fileio_data_t *)calloc(1, sizeof(fileio_data_t));
dat->control_fd = st_netfd_open(fd_control);
dat->data_fd = st_netfd_open(fd_out);
dat->pid = pid;
st_netfd_setspecific(fd, dat, fileio_data_destructor);
}
}
return dat;
}
/**
* Read data from the specified section of a file. Uses a forked
* file_reader process to do the actual reading so as to avoid causing all
* State Threads to block.
*
* @param fd must refer to a seekable file.
* @param offset absolute offset within the file
* @param buf output buffer
* @param nbytes size of the output buffer
* @param timeout
*/
ssize_t
stx_file_read(st_netfd_t fd, off_t offset, void *buf, size_t nbytes, st_utime_t timeout)
{
fileio_data_t *dat = get_fileio_data(fd);
if (dat) {
file_reader_cb_t cb;
ssize_t ret = (ssize_t)-1;
cb.offset = offset;
cb.nbytes = nbytes;
st_write(dat->control_fd, (char *)&cb, sizeof(cb), timeout);
if (sizeof(ret) == st_read(dat->data_fd, (char *)&ret, sizeof(ret), timeout) && 0 < ret && ret <= nbytes) {
return st_read(dat->data_fd, buf, ret, timeout);
} else {
return ret;
}
}
return (ssize_t)-1;
}

View file

@ -1,52 +0,0 @@
/*
* File I/O extension to the State Threads Library.
*/
/*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is the file I/O extension to the State Threads Library.
*
* The Initial Developer of the Original Code is Jeff
* <jlb-st@houseofdistraction.com>. Portions created by the Initial
* Developer are Copyright (C) 2002 the Initial Developer. All Rights
* Reserved.
*
* Contributor(s): (none)
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU General Public License Version 2 or later (the
* "GPL"), in which case the provisions of the GPL are applicable
* instead of those above. If you wish to allow use of your
* version of this file only under the terms of the GPL and not to
* allow others to use your version of this file under the MPL,
* indicate your decision by deleting the provisions above and
* replace them with the notice and other provisions required by
* the GPL. If you do not delete the provisions above, a recipient
* may use your version of this file under either the MPL or the
* GPL.
*/
#ifndef __STX_FILEIO_H__
#define __STX_FILEIO_H__
#include <st.h>
#ifdef __cplusplus
extern "C" {
#endif
extern ssize_t stx_file_read(st_netfd_t fd, off_t offset, void *buf, size_t nbytes, st_utime_t timeout);
#ifdef __cplusplus
}
#endif
#endif /* !__STX_FILEIO_H__ */

View file

@ -1,112 +0,0 @@
#include "stx.h"
#include <netinet/in.h>
#include <arpa/inet.h>
#define MAX_ADDRS 128
#define TIMEOUT (4*1000000LL)
static void do_resolve(const char *host)
{
struct in_addr addrs[MAX_ADDRS];
int i, n = MAX_ADDRS;
if (stx_dns_getaddrlist(host, addrs, &n, TIMEOUT) < 0) {
fprintf(stderr, "stx_dns_getaddrlist: can't resolve %s: ", host);
if (h_errno == NETDB_INTERNAL)
perror("");
else
herror("");
} else {
if (n > 0)
printf("%-40s %s\n", (char *)host, inet_ntoa(addrs[0]));
for (i = 1; i < n; i++)
printf("%-40s %s\n", "", inet_ntoa(addrs[i]));
}
}
static void show_info(void)
{
stx_cache_info_t info;
stx_dns_cache_getinfo(&info);
printf("DNS cache info:\n\n");
printf("max_size: %8d\n", (int)info.max_size);
printf("capacity: %8d bytes\n", (int)info.max_weight);
printf("hash_size: %8d\n", (int)info.hash_size);
printf("cur_size: %8d\n"
"cur_mem: %8d bytes\n"
"hits: %8d\n"
"lookups: %8d\n"
"inserts: %8d\n"
"deletes: %8d\n",
(int)info.cur_size, (int)info.cur_weight, (int)info.hits,
(int)info.lookups, (int)info.inserts, (int)info.deletes);
}
extern stx_cache_t *_stx_dns_cache;
static void printhost(void *host, void *data)
{
printf("%s\n", (char *)host);
}
static void show_lru(void)
{
printf("LRU hosts:\n\n");
stx_cache_traverse_lru(_stx_dns_cache, printhost, 10);
}
static void show_mru(void)
{
printf("MRU hosts:\n\n");
stx_cache_traverse_mru(_stx_dns_cache, printhost, 10);
}
static void flush_cache(void)
{
stx_cache_empty(_stx_dns_cache);
printf("DNS cache is empty\n");
}
int main()
{
char line[256];
char str[sizeof(line)];
st_init();
stx_dns_cache_init(100, 10000, 101);
for ( ; ; ) {
fputs("> ", stdout);
fflush(stdout);
if (!fgets(line, sizeof(line), stdin))
break;
if (sscanf(line, "%s", str) != 1)
continue;
if (strcmp(str, "exit") == 0 || strcmp(str, "quit") == 0)
break;
if (strcmp(str, "info") == 0) {
show_info();
continue;
}
if (strcmp(str, "lru") == 0) {
show_lru();
continue;
}
if (strcmp(str, "mru") == 0) {
show_mru();
continue;
}
if (strcmp(str, "flush") == 0) {
flush_cache();
continue;
}
do_resolve(str);
}
return 0;
}

View file

@ -68,8 +68,6 @@ unsigned long long _st_stat_recvmsg = 0;
unsigned long long _st_stat_recvmsg_eagain = 0;
unsigned long long _st_stat_sendmsg = 0;
unsigned long long _st_stat_sendmsg_eagain = 0;
unsigned long long _st_stat_sendmmsg = 0;
unsigned long long _st_stat_sendmmsg_eagain = 0;
#endif
#if EAGAIN != EWOULDBLOCK
@ -262,7 +260,6 @@ int st_netfd_poll(_st_netfd_t *fd, int how, st_utime_t timeout)
}
#ifdef MD_ALWAYS_UNSERIALIZED_ACCEPT
/* No-op */
int st_netfd_serialize_accept(_st_netfd_t *fd)
{
@ -310,112 +307,6 @@ _st_netfd_t *st_accept(_st_netfd_t *fd, struct sockaddr *addr, int *addrlen, st_
return newfd;
}
#else /* MD_ALWAYS_UNSERIALIZED_ACCEPT */
/*
* On some platforms accept() calls from different processes
* on the same listen socket must be serialized.
* The following code serializes accept()'s without process blocking.
* A pipe is used as an inter-process semaphore.
*/
int st_netfd_serialize_accept(_st_netfd_t *fd)
{
_st_netfd_t **p;
int osfd[2], err;
if (fd->aux_data) {
errno = EINVAL;
return -1;
}
if ((p = (_st_netfd_t **)calloc(2, sizeof(_st_netfd_t *))) == NULL)
return -1;
if (pipe(osfd) < 0) {
free(p);
return -1;
}
if ((p[0] = st_netfd_open(osfd[0])) != NULL && (p[1] = st_netfd_open(osfd[1])) != NULL && write(osfd[1], " ", 1) == 1) {
fd->aux_data = p;
return 0;
}
/* Error */
err = errno;
if (p[0])
st_netfd_free(p[0]);
if (p[1])
st_netfd_free(p[1]);
close(osfd[0]);
close(osfd[1]);
free(p);
errno = err;
return -1;
}
static void _st_netfd_free_aux_data(_st_netfd_t *fd)
{
_st_netfd_t **p = (_st_netfd_t **) fd->aux_data;
st_netfd_close(p[0]);
st_netfd_close(p[1]);
free(p);
fd->aux_data = NULL;
}
_st_netfd_t *st_accept(_st_netfd_t *fd, struct sockaddr *addr, int *addrlen, st_utime_t timeout)
{
int osfd, err;
_st_netfd_t *newfd;
_st_netfd_t **p = (_st_netfd_t **) fd->aux_data;
ssize_t n;
char c;
for ( ; ; ) {
if (p == NULL) {
osfd = accept(fd->osfd, addr, (socklen_t *)addrlen);
} else {
/* Get the lock */
n = st_read(p[0], &c, 1, timeout);
if (n < 0)
return NULL;
ST_ASSERT(n == 1);
/* Got the lock */
osfd = accept(fd->osfd, addr, (socklen_t *)addrlen);
/* Unlock */
err = errno;
n = st_write(p[1], &c, 1, timeout);
ST_ASSERT(n == 1);
errno = err;
}
if (osfd >= 0)
break;
if (errno == EINTR)
continue;
if (!_IO_NOT_READY_ERROR)
return NULL;
/* Wait until the socket becomes readable */
if (st_netfd_poll(fd, POLLIN, timeout) < 0)
return NULL;
}
/* On some platforms the new socket created by accept() inherits */
/* the nonblocking attribute of the listening socket */
#if defined (MD_ACCEPT_NB_INHERITED)
newfd = _st_netfd_new(osfd, 0, 1);
#elif defined (MD_ACCEPT_NB_NOT_INHERITED)
newfd = _st_netfd_new(osfd, 1, 1);
#else
#error Unknown OS
#endif
if (!newfd) {
err = errno;
close(osfd);
errno = err;
}
return newfd;
}
#endif /* MD_ALWAYS_UNSERIALIZED_ACCEPT */
int st_connect(_st_netfd_t *fd, const struct sockaddr *addr, int addrlen, st_utime_t timeout)
{
@ -833,69 +724,6 @@ int st_sendmsg(_st_netfd_t *fd, const struct msghdr *msg, int flags, st_utime_t
return n;
}
int st_sendmmsg(st_netfd_t fd, struct st_mmsghdr *msgvec, unsigned int vlen, int flags, st_utime_t timeout)
{
#if defined(MD_HAVE_SENDMMSG) && defined(_GNU_SOURCE)
int n;
int left;
struct mmsghdr *p;
#if defined(DEBUG) && defined(DEBUG_STATS)
++_st_stat_sendmmsg;
#endif
left = (int)vlen;
while (left > 0) {
p = (struct mmsghdr*)msgvec + (vlen - left);
if ((n = sendmmsg(fd->osfd, p, left, flags)) < 0) {
if (errno == EINTR)
continue;
if (!_IO_NOT_READY_ERROR)
break;
#if defined(DEBUG) && defined(DEBUG_STATS)
++_st_stat_sendmmsg_eagain;
#endif
/* Wait until the socket becomes writable */
if (st_netfd_poll(fd, POLLOUT, timeout) < 0)
break;
}
left -= n;
}
// An error is returned only if no datagrams could be sent.
if (left == (int)vlen) {
return n;
}
return (int)vlen - left;
#else
struct st_mmsghdr *p;
int i, n;
// @see http://man7.org/linux/man-pages/man2/sendmmsg.2.html
for (i = 0; i < (int)vlen; ++i) {
p = msgvec + i;
n = st_sendmsg(fd, &p->msg_hdr, flags, timeout);
if (n < 0) {
// An error is returned only if no datagrams could be sent.
if (i == 0) {
return n;
}
return i + 1;
}
p->msg_len = n;
}
// Returns the number of messages sent from msgvec; if this is less than vlen, the caller can retry with a
// further sendmmsg() call to send the remaining messages.
return vlen;
#endif
}
/*
* To open FIFOs or other special files.

View file

@ -1,51 +0,0 @@
EXPORTS
st_accept @62
st_cond_broadcast @63
st_cond_destroy @64
st_cond_new @65
st_cond_signal @66
st_cond_timedwait @67
st_cond_wait @68
st_connect @69
st_getfdlimit @70
st_init @71
st_key_create @72
st_key_getlimit @73
st_mutex_destroy @74
st_mutex_lock @75
st_mutex_new @76
st_mutex_trylock @77
st_mutex_unlock @78
st_netfd_close @79
st_netfd_fileno @80
st_netfd_free @81
st_netfd_getspecific @82
st_netfd_open @83
st_netfd_open_socket @84
st_netfd_poll @85
st_netfd_serialize_accept @86
st_netfd_setspecific @87
st_open @88
st_poll @89
st_randomize_stacks @90
st_read @91
st_read_fully @92
st_read_resid @93
st_recvfrom @94
st_sendto @95
st_sleep @96
st_thread_create @97
st_thread_exit @98
st_thread_getspecific @99
st_thread_interrupt @100
st_thread_join @101
st_thread_self @102
st_thread_setspecific @103
st_time @104
st_timecache_set @105
st_usleep @106
st_utime @107
st_utime_last_clock @108
st_write @109
st_write_resid @110
st_writev @111

View file

@ -58,66 +58,10 @@
* Platform specifics
*/
#if defined (AIX)
#if defined (DARWIN)
#define MD_STACK_GROWS_DOWN
#define MD_USE_SYSV_ANON_MMAP
#define MD_ACCEPT_NB_INHERITED
#define MD_ALWAYS_UNSERIALIZED_ACCEPT
#ifndef MD_HAVE_SOCKLEN_T
#define MD_HAVE_SOCKLEN_T
#define socklen_t unsigned long
#endif
#define MD_SETJMP(env) _setjmp(env)
#define MD_LONGJMP(env, val) _longjmp(env, val)
#define MD_INIT_CONTEXT(_thread, _sp, _main) \
ST_BEGIN_MACRO \
if (MD_SETJMP((_thread)->context)) \
_main(); \
(_thread)->context[3] = (long) (_sp); \
ST_END_MACRO
#define MD_GET_UTIME() \
timebasestruct_t rt; \
(void) read_real_time(&rt, TIMEBASE_SZ); \
(void) time_base_to_time(&rt, TIMEBASE_SZ); \
return (rt.tb_high * 1000000LL + rt.tb_low / 1000)
#elif defined (CYGWIN)
#define MD_STACK_GROWS_DOWN
#define MD_USE_BSD_ANON_MMAP
#define MD_ACCEPT_NB_NOT_INHERITED
#define MD_ALWAYS_UNSERIALIZED_ACCEPT
#define MD_SETJMP(env) setjmp(env)
#define MD_LONGJMP(env, val) longjmp(env, val)
#define MD_JB_SP 7
#define MD_GET_SP(_t) (_t)->context[MD_JB_SP]
#define MD_INIT_CONTEXT(_thread, _sp, _main) \
ST_BEGIN_MACRO \
if (MD_SETJMP((_thread)->context)) \
_main(); \
MD_GET_SP(_thread) = (long) (_sp); \
ST_END_MACRO
#define MD_GET_UTIME() \
struct timeval tv; \
(void) gettimeofday(&tv, NULL); \
return (tv.tv_sec * 1000000LL + tv.tv_usec)
#elif defined (DARWIN)
#define MD_STACK_GROWS_DOWN
#define MD_USE_BSD_ANON_MMAP
#define MD_ACCEPT_NB_INHERITED
#define MD_ALWAYS_UNSERIALIZED_ACCEPT
#define MD_HAVE_SOCKLEN_T
#define MD_USE_BUILTIN_SETJMP
@ -149,123 +93,6 @@
(void) gettimeofday(&tv, NULL); \
return (tv.tv_sec * 1000000LL + tv.tv_usec)
#elif defined (FREEBSD)
#define MD_STACK_GROWS_DOWN
#define MD_USE_BSD_ANON_MMAP
#define MD_ACCEPT_NB_INHERITED
#define MD_ALWAYS_UNSERIALIZED_ACCEPT
#define MD_SETJMP(env) _setjmp(env)
#define MD_LONGJMP(env, val) _longjmp(env, val)
#if defined(__i386__)
#define MD_JB_SP 2
#elif defined(__alpha__)
#define MD_JB_SP 34
#elif defined(__amd64__)
#define MD_JB_SP 2
#else
#error Unknown CPU architecture
#endif
#define MD_INIT_CONTEXT(_thread, _sp, _main) \
ST_BEGIN_MACRO \
if (MD_SETJMP((_thread)->context)) \
_main(); \
(_thread)->context[0]._jb[MD_JB_SP] = (long) (_sp); \
ST_END_MACRO
#define MD_GET_UTIME() \
struct timeval tv; \
(void) gettimeofday(&tv, NULL); \
return (tv.tv_sec * 1000000LL + tv.tv_usec)
#elif defined (HPUX)
#define MD_STACK_GROWS_UP
#define MD_USE_BSD_ANON_MMAP
#define MD_ACCEPT_NB_INHERITED
#define MD_ALWAYS_UNSERIALIZED_ACCEPT
#define MD_SETJMP(env) _setjmp(env)
#define MD_LONGJMP(env, val) _longjmp(env, val)
#ifndef __LP64__
/* 32-bit mode (ILP32 data model) */
#define MD_INIT_CONTEXT(_thread, _sp, _main) \
ST_BEGIN_MACRO \
if (MD_SETJMP((_thread)->context)) \
_main(); \
((long *)((_thread)->context))[1] = (long) (_sp); \
ST_END_MACRO
#else
/* 64-bit mode (LP64 data model) */
#define MD_STACK_PAD_SIZE 256
/* Last stack frame must be preserved */
#define MD_INIT_CONTEXT(_thread, _sp, _main) \
ST_BEGIN_MACRO \
if (MD_SETJMP((_thread)->context)) \
_main(); \
memcpy((char *)(_sp) - MD_STACK_PAD_SIZE, \
((char **)((_thread)->context))[1] - MD_STACK_PAD_SIZE, \
MD_STACK_PAD_SIZE); \
((long *)((_thread)->context))[1] = (long) (_sp); \
ST_END_MACRO
#endif /* !__LP64__ */
#define MD_GET_UTIME() \
struct timeval tv; \
(void) gettimeofday(&tv, NULL); \
return (tv.tv_sec * 1000000LL + tv.tv_usec)
#elif defined (IRIX)
#include <sys/syssgi.h>
#define MD_STACK_GROWS_DOWN
#define MD_USE_SYSV_ANON_MMAP
#define MD_ACCEPT_NB_INHERITED
#define MD_ALWAYS_UNSERIALIZED_ACCEPT
#define MD_SETJMP(env) setjmp(env)
#define MD_LONGJMP(env, val) longjmp(env, val)
#define MD_INIT_CONTEXT(_thread, _sp, _main) \
ST_BEGIN_MACRO \
(void) MD_SETJMP((_thread)->context); \
(_thread)->context[JB_SP] = (long) (_sp); \
(_thread)->context[JB_PC] = (long) _main; \
ST_END_MACRO
#define MD_GET_UTIME() \
static int inited = 0; \
static clockid_t clock_id = CLOCK_SGI_CYCLE; \
struct timespec ts; \
if (!inited) { \
if (syssgi(SGI_CYCLECNTR_SIZE) < 64) \
clock_id = CLOCK_REALTIME; \
inited = 1; \
} \
(void) clock_gettime(clock_id, &ts); \
return (ts.tv_sec * 1000000LL + ts.tv_nsec / 1000)
/*
* Cap the stack by zeroing out the saved return address register
* value. This allows libexc, used by SpeedShop, to know when to stop
* backtracing since it won't find main, start, or any other known
* stack root function in a state thread's stack. Without this libexc
* traces right off the stack and crashes.
* The function preamble stores ra at 8(sp), this stores zero there.
* N.B. This macro is compiler/ABI dependent. It must change if ANY more
* automatic variables are added to the _st_thread_main() routine, because
* the address where ra is stored will change.
*/
#if !defined(__GNUC__) && defined(_MIPS_SIM) && _MIPS_SIM != _ABIO32
#define MD_CAP_STACK(var_addr) \
(((volatile __uint64_t *)(var_addr))[1] = 0)
#endif
#elif defined (LINUX)
/*
@ -274,7 +101,6 @@
*/
#define MD_USE_BSD_ANON_MMAP
#define MD_ACCEPT_NB_NOT_INHERITED
#define MD_ALWAYS_UNSERIALIZED_ACCEPT
/*
* Modern GNU/Linux is Posix.1g compliant.
*/
@ -289,38 +115,7 @@
(void) gettimeofday(&tv, NULL); \
return (tv.tv_sec * 1000000LL + tv.tv_usec)
#if defined(__ia64__)
#define MD_STACK_GROWS_DOWN
/*
* IA-64 architecture. Besides traditional memory call stack, IA-64
* uses general register stack. Thus each thread needs a backing store
* for register stack in addition to memory stack. Standard
* setjmp()/longjmp() cannot be used for thread context switching
* because their implementation implicitly assumes that only one
* register stack exists.
*/
#ifdef USE_LIBC_SETJMP
#undef USE_LIBC_SETJMP
#endif
#define MD_USE_BUILTIN_SETJMP
#define MD_STACK_PAD_SIZE 128
/* Last register stack frame must be preserved */
#define MD_INIT_CONTEXT(_thread, _sp, _bsp, _main) \
ST_BEGIN_MACRO \
if (MD_SETJMP((_thread)->context)) \
_main(); \
memcpy((char *)(_bsp) - MD_STACK_PAD_SIZE, \
(char *)(_thread)->context[0].__jmpbuf[17] - MD_STACK_PAD_SIZE, \
MD_STACK_PAD_SIZE); \
(_thread)->context[0].__jmpbuf[0] = (long) (_sp); \
(_thread)->context[0].__jmpbuf[17] = (long) (_bsp); \
ST_END_MACRO
#elif defined(__mips__)
#define MD_STACK_GROWS_DOWN
#if defined(__mips__)
#define MD_INIT_CONTEXT(_thread, _sp, _main) \
ST_BEGIN_MACRO \
MD_SETJMP((_thread)->context); \
@ -328,7 +123,7 @@
_thread->context[0].__jmpbuf[0].__sp = _sp; \
ST_END_MACRO
#else /* Not IA-64 or mips */
#else /* Not mips */
/*
* On linux, there are a few styles of jmpbuf format. These vary based
@ -350,56 +145,7 @@
* unless USE_LIBC_SETJMP is defined.
*/
#if defined(__powerpc__)
#define MD_STACK_GROWS_DOWN
#if (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1)
#ifndef JB_GPR1
#define JB_GPR1 0
#endif
#define MD_GET_SP(_t) (_t)->context[0].__jmpbuf[JB_GPR1]
#else
/* not an error but certainly cause for caution */
#error "Untested use of old glibc on powerpc"
#define MD_GET_SP(_t) (_t)->context[0].__jmpbuf[0].__misc[0]
#endif /* glibc 2.1 or later */
#elif defined(__alpha)
#define MD_STACK_GROWS_DOWN
#if defined(__GLIBC__) && __GLIBC__ >= 2
#ifndef JB_SP
#define JB_SP 8
#endif
#define MD_GET_SP(_t) (_t)->context[0].__jmpbuf[JB_SP]
#else
/* not an error but certainly cause for caution */
#error "Untested use of old glibc on alpha"
#define MD_GET_SP(_t) (_t)->context[0].__jmpbuf[0].__sp
#endif
#elif defined(__mc68000__)
#define MD_STACK_GROWS_DOWN
/* m68k still uses old style sigjmp_buf */
#define MD_GET_SP(_t) (_t)->context[0].__jmpbuf[0].__sp
#elif defined(__sparc__)
#define MD_STACK_GROWS_DOWN
#if defined(__GLIBC__) && __GLIBC__ >= 2
#ifndef JB_SP
#define JB_SP 0
#endif
#define MD_GET_SP(_t) (_t)->context[0].__jmpbuf[JB_SP]
#else
/* not an error but certainly cause for caution */
#error "Untested use of old glic on sparc -- also using odd mozilla derived __fp"
#define MD_GET_SP(_t) (_t)->context[0].__jmpbuf[0].__fp
#endif
#elif defined(__i386__)
#define MD_STACK_GROWS_DOWN
#if defined(__i386__)
#define MD_USE_BUILTIN_SETJMP
#if defined(__GLIBC__) && __GLIBC__ >= 2
@ -414,7 +160,6 @@
#endif
#elif defined(__amd64__) || defined(__x86_64__)
#define MD_STACK_GROWS_DOWN
#define MD_USE_BUILTIN_SETJMP
#ifndef JB_RSP
@ -424,12 +169,10 @@
#elif defined(__aarch64__)
/* https://github.com/ossrs/state-threads/issues/9 */
#define MD_STACK_GROWS_DOWN
#define MD_USE_BUILTIN_SETJMP
#define MD_GET_SP(_t) (_t)->context[0].__jmpbuf[13]
#elif defined(__arm__)
#define MD_STACK_GROWS_DOWN
/* https://github.com/ossrs/state-threads/issues/1#issuecomment-244648573 */
#define MD_USE_BUILTIN_SETJMP
@ -445,22 +188,6 @@
#error "ARM/Linux pre-glibc2 not supported yet"
#endif /* defined(__GLIBC__) && __GLIBC__ >= 2 */
#elif defined(__s390__)
#define MD_STACK_GROWS_DOWN
/* There is no JB_SP in glibc at this time. (glibc 2.2.5)
*/
#define MD_GET_SP(_t) (_t)->context[0].__jmpbuf[0].__gregs[9]
#elif defined(__hppa__)
#define MD_STACK_GROWS_UP
/* yes, this is gross, unfortunately at the moment (2002/08/01) there is
* a bug in hppa's glibc header definition for JB_SP, so we can't
* use that...
*/
#define MD_GET_SP(_t) (*(long *)(((char *)&(_t)->context[0].__jmpbuf[0]) + 76))
#else
#error "Unknown CPU architecture"
#endif /* Cases with common MD_INIT_CONTEXT and different SP locations */
@ -485,150 +212,10 @@
#define MD_LONGJMP(env, val) longjmp(env, val)
#endif
#elif defined (NETBSD)
#define MD_STACK_GROWS_DOWN
#define MD_USE_BSD_ANON_MMAP
#define MD_ACCEPT_NB_INHERITED
#define MD_ALWAYS_UNSERIALIZED_ACCEPT
#define MD_HAVE_SOCKLEN_T
#define MD_SETJMP(env) _setjmp(env)
#define MD_LONGJMP(env, val) _longjmp(env, val)
#if defined(__i386__)
#define MD_JB_SP 2
#elif defined(__alpha__)
#define MD_JB_SP 34
#elif defined(__sparc__)
#define MD_JB_SP 0
#elif defined(__vax__)
#define MD_JB_SP 2
#else
#error Unknown CPU architecture
#endif
#define MD_INIT_CONTEXT(_thread, _sp, _main) \
ST_BEGIN_MACRO \
if (MD_SETJMP((_thread)->context)) \
_main(); \
(_thread)->context[MD_JB_SP] = (long) (_sp); \
ST_END_MACRO
#define MD_GET_UTIME() \
struct timeval tv; \
(void) gettimeofday(&tv, NULL); \
return (tv.tv_sec * 1000000LL + tv.tv_usec)
#elif defined (OPENBSD)
#define MD_STACK_GROWS_DOWN
#define MD_USE_BSD_ANON_MMAP
#define MD_ACCEPT_NB_INHERITED
#define MD_ALWAYS_UNSERIALIZED_ACCEPT
#define MD_SETJMP(env) _setjmp(env)
#define MD_LONGJMP(env, val) _longjmp(env, val)
#if defined(__i386__)
#define MD_JB_SP 2
#elif defined(__alpha__)
#define MD_JB_SP 34
#elif defined(__sparc__)
#define MD_JB_SP 0
#elif defined(__amd64__)
#define MD_JB_SP 6
#else
#error Unknown CPU architecture
#endif
#define MD_INIT_CONTEXT(_thread, _sp, _main) \
ST_BEGIN_MACRO \
if (MD_SETJMP((_thread)->context)) \
_main(); \
(_thread)->context[MD_JB_SP] = (long) (_sp); \
ST_END_MACRO
#define MD_GET_UTIME() \
struct timeval tv; \
(void) gettimeofday(&tv, NULL); \
return (tv.tv_sec * 1000000LL + tv.tv_usec)
#elif defined (OSF1)
#include <signal.h>
#define MD_STACK_GROWS_DOWN
#define MD_USE_SYSV_ANON_MMAP
#define MD_ACCEPT_NB_NOT_INHERITED
#define MD_ALWAYS_UNSERIALIZED_ACCEPT
#define MD_SETJMP(env) _setjmp(env)
#define MD_LONGJMP(env, val) _longjmp(env, val)
#define MD_INIT_CONTEXT(_thread, _sp, _main) \
ST_BEGIN_MACRO \
if (MD_SETJMP((_thread)->context)) \
_main(); \
((struct sigcontext *)((_thread)->context))->sc_sp = (long) (_sp); \
ST_END_MACRO
#define MD_GET_UTIME() \
struct timeval tv; \
(void) gettimeofday(&tv, NULL); \
return (tv.tv_sec * 1000000LL + tv.tv_usec)
#elif defined (SOLARIS)
#include <sys/filio.h>
extern int getpagesize(void);
#define MD_STACK_GROWS_DOWN
#define MD_USE_SYSV_ANON_MMAP
#define MD_ACCEPT_NB_NOT_INHERITED
#define MD_SETJMP(env) setjmp(env)
#define MD_LONGJMP(env, val) longjmp(env, val)
#if defined(sparc) || defined(__sparc)
#ifdef _LP64
#define MD_STACK_PAD_SIZE 4095
#endif
#define MD_INIT_CONTEXT(_thread, _sp, _main) \
ST_BEGIN_MACRO \
(void) MD_SETJMP((_thread)->context); \
(_thread)->context[1] = (long) (_sp); \
(_thread)->context[2] = (long) _main; \
ST_END_MACRO
#elif defined(i386) || defined(__i386)
#define MD_INIT_CONTEXT(_thread, _sp, _main) \
ST_BEGIN_MACRO \
(void) MD_SETJMP((_thread)->context); \
(_thread)->context[4] = (long) (_sp); \
(_thread)->context[5] = (long) _main; \
ST_END_MACRO
#elif defined(__amd64__)
#define MD_INIT_CONTEXT(_thread, _sp, _main) \
ST_BEGIN_MACRO \
if (MD_SETJMP((_thread)->context)) \
_main(); \
(_thread)->context[6] = (long) (_sp); \
ST_END_MACRO
#else
#error Unknown CPU architecture
#endif
#define MD_GET_UTIME() \
return (gethrtime() / 1000)
#else
#error Unknown OS
#endif /* OS */
#if !defined(MD_HAVE_POLL) && !defined(MD_DONT_HAVE_POLL)
#define MD_HAVE_POLL
#endif
#ifndef MD_STACK_PAD_SIZE
#define MD_STACK_PAD_SIZE 128
#endif

View file

@ -7,299 +7,7 @@
* All Rights Reserved.
*/
#if defined(__ia64__)
/****************************************************************/
/*
* The internal __jmp_buf layout is different from one used
* by setjmp()/longjmp().
*
* Offset Description
* ------ -----------
* 0x000 stack pointer (r12)
* 0x008 gp (r1)
* 0x010 caller's unat
* 0x018 fpsr
* 0x020 r4
* 0x028 r5
* 0x030 r6
* 0x038 r7
* 0x040 rp (b0)
* 0x048 b1
* 0x050 b2
* 0x058 b3
* 0x060 b4
* 0x068 b5
* 0x070 ar.pfs
* 0x078 ar.lc
* 0x080 pr
* 0x088 ar.bsp
* 0x090 ar.unat
* 0x098 &__jmp_buf
* 0x0a0 ar.rsc
* 0x0a8 ar.rnat
* 0x0b0 f2
* 0x0c0 f3
* 0x0d0 f4
* 0x0e0 f5
* 0x0f0 f16
* 0x100 f17
* 0x110 f18
* 0x120 f19
* 0x130 f20
* 0x130 f21
* 0x140 f22
* 0x150 f23
* 0x160 f24
* 0x170 f25
* 0x180 f26
* 0x190 f27
* 0x1a0 f28
* 0x1b0 f29
* 0x1c0 f30
* 0x1d0 f31
*
* Note that the address of __jmp_buf is saved but not used: we assume
* that the jmp_buf data structure is never moved around in memory.
*/
/*
* Implemented according to "IA-64 Software Conventions and Runtime
* Architecture Guide", Chapter 10: "Context Management".
*/
.text
.psr abi64
.psr lsb
.lsb
/* _st_md_cxt_save(__jmp_buf env) */
.align 32
.global _st_md_cxt_save
.proc _st_md_cxt_save
_st_md_cxt_save:
alloc r14 = ar.pfs,1,0,0,0
mov r16 = ar.unat
;;
mov r17 = ar.fpsr
mov r2 = in0
add r3 = 8,in0
;;
st8.spill.nta [r2] = sp,16 // r12 (sp)
;;
st8.spill.nta [r3] = gp,16 // r1 (gp)
;;
st8.nta [r2] = r16,16 // save caller's unat
st8.nta [r3] = r17,16 // save fpsr
add r8 = 0xb0,in0
;;
st8.spill.nta [r2] = r4,16 // r4
;;
st8.spill.nta [r3] = r5,16 // r5
add r9 = 0xc0,in0
;;
stf.spill.nta [r8] = f2,32
stf.spill.nta [r9] = f3,32
mov r15 = rp
;;
stf.spill.nta [r8] = f4,32
stf.spill.nta [r9] = f5,32
mov r17 = b1
;;
stf.spill.nta [r8] = f16,32
stf.spill.nta [r9] = f17,32
mov r18 = b2
;;
stf.spill.nta [r8] = f18,32
stf.spill.nta [r9] = f19,32
mov r19 = b3
;;
stf.spill.nta [r8] = f20,32
stf.spill.nta [r9] = f21,32
mov r20 = b4
;;
stf.spill.nta [r8] = f22,32
stf.spill.nta [r9] = f23,32
mov r21 = b5
;;
stf.spill.nta [r8] = f24,32
stf.spill.nta [r9] = f25,32
mov r22 = ar.lc
;;
stf.spill.nta [r8] = f26,32
stf.spill.nta [r9] = f27,32
mov r24 = pr
;;
stf.spill.nta [r8] = f28,32
stf.spill.nta [r9] = f29,32
;;
stf.spill.nta [r8] = f30
stf.spill.nta [r9] = f31
st8.spill.nta [r2] = r6,16 // r6
;;
st8.spill.nta [r3] = r7,16 // r7
;;
mov r23 = ar.bsp
mov r25 = ar.unat
st8.nta [r2] = r15,16 // b0
st8.nta [r3] = r17,16 // b1
;;
st8.nta [r2] = r18,16 // b2
st8.nta [r3] = r19,16 // b3
mov r26 = ar.rsc
;;
st8.nta [r2] = r20,16 // b4
st8.nta [r3] = r21,16 // b5
;;
st8.nta [r2] = r14,16 // ar.pfs
st8.nta [r3] = r22,16 // ar.lc
;;
st8.nta [r2] = r24,16 // pr
st8.nta [r3] = r23,16 // ar.bsp
;;
st8.nta [r2] = r25,16 // ar.unat
st8.nta [r3] = in0,16 // &__jmp_buf (just in case)
;;
st8.nta [r2] = r26 // ar.rsc
;;
flushrs // flush dirty regs to backing store
;;
and r27 = ~0x3,r26 // clear ar.rsc.mode
;;
mov ar.rsc = r27 // put RSE in enforced lazy mode
;;
mov r28 = ar.rnat
;;
st8.nta [r3] = r28 // ar.rnat
mov ar.rsc = r26 // restore ar.rsc
;;
mov r8 = 0
br.ret.sptk.few b0
.endp _st_md_cxt_save
/****************************************************************/
/* _st_md_cxt_restore(__jmp_buf env, int val) */
.global _st_md_cxt_restore
.proc _st_md_cxt_restore
_st_md_cxt_restore:
alloc r8 = ar.pfs,2,0,0,0
add r2 = 0x88,in0 // r2 <- &jmpbuf.ar_bsp
mov r16 = ar.rsc
;;
flushrs // flush dirty regs to backing store
;;
and r17 = ~0x3,r16 // clear ar.rsc.mode
;;
mov ar.rsc = r17 // put RSE in enforced lazy mode
;;
invala // invalidate the ALAT
;;
ld8 r23 = [r2],8 // r23 <- jmpbuf.ar_bsp
;;
mov ar.bspstore = r23 // write BSPSTORE
ld8 r25 = [r2],24 // r25 <- jmpbuf.ar_unat
;;
ld8 r26 = [r2],-8 // r26 <- jmpbuf.ar_rnat
;;
mov ar.rnat = r26 // write RNAT
ld8 r27 = [r2] // r27 <- jmpbuf.ar_rsc
;;
mov ar.rsc = r27 // write RSE control
mov r2 = in0
;;
mov ar.unat = r25 // write ar.unat
add r3 = 8,in0
;;
ld8.fill.nta sp = [r2],16 // r12 (sp)
ld8.fill.nta gp = [r3],16 // r1 (gp)
;;
ld8.nta r16 = [r2],16 // caller's unat
ld8.nta r17 = [r3],16 // fpsr
;;
ld8.fill.nta r4 = [r2],16 // r4
ld8.fill.nta r5 = [r3],16 // r5
;;
ld8.fill.nta r6 = [r2],16 // r6
ld8.fill.nta r7 = [r3],16 // r7
;;
mov ar.unat = r16 // restore caller's unat
mov ar.fpsr = r17 // restore fpsr
;;
ld8.nta r16 = [r2],16 // b0
ld8.nta r17 = [r3],16 // b1
;;
ld8.nta r18 = [r2],16 // b2
ld8.nta r19 = [r3],16 // b3
;;
ld8.nta r20 = [r2],16 // b4
ld8.nta r21 = [r3],16 // b5
;;
ld8.nta r11 = [r2],16 // ar.pfs
ld8.nta r22 = [r3],72 // ar.lc
;;
ld8.nta r24 = [r2],48 // pr
mov b0 = r16
;;
ldf.fill.nta f2 = [r2],32
ldf.fill.nta f3 = [r3],32
mov b1 = r17
;;
ldf.fill.nta f4 = [r2],32
ldf.fill.nta f5 = [r3],32
mov b2 = r18
;;
ldf.fill.nta f16 = [r2],32
ldf.fill.nta f17 = [r3],32
mov b3 = r19
;;
ldf.fill.nta f18 = [r2],32
ldf.fill.nta f19 = [r3],32
mov b4 = r20
;;
ldf.fill.nta f20 = [r2],32
ldf.fill.nta f21 = [r3],32
mov b5 = r21
;;
ldf.fill.nta f22 = [r2],32
ldf.fill.nta f23 = [r3],32
mov ar.lc = r22
;;
ldf.fill.nta f24 = [r2],32
ldf.fill.nta f25 = [r3],32
cmp.eq p6,p7 = 0,in1
;;
ldf.fill.nta f26 = [r2],32
ldf.fill.nta f27 = [r3],32
mov ar.pfs = r11
;;
ldf.fill.nta f28 = [r2],32
ldf.fill.nta f29 = [r3],32
;;
ldf.fill.nta f30 = [r2]
ldf.fill.nta f31 = [r3]
(p6) mov r8 = 1
(p7) mov r8 = in1
mov pr = r24,-1
br.ret.sptk.few b0
.endp _st_md_cxt_restore
/****************************************************************/
#elif defined(__i386__)
#if defined(__i386__)
/****************************************************************/

View file

@ -1,45 +0,0 @@
#
# This script can be used to automatically guess target OS.
# It requires the config.guess utility which is a part of GNU Autoconf.
# GNU Autoconf can be downloaded from ftp://ftp.gnu.org/gnu/autoconf/
#
# Use "default" as a make target for automatic builds.
#
# Specify path to the config.guess utility (unless set via environment)
#CONFIG_GUESS_PATH=
if [ x"$CONFIG_GUESS_PATH" = x ]; then
echo "Error: CONFIG_GUESS_PATH variable is not set"
exit 1
fi
if [ ! -f "$CONFIG_GUESS_PATH/config.guess" ]; then
echo "Can't find $CONFIG_GUESS_PATH/config.guess utility. Wrong path?"
exit 1
fi
sys_info=`/bin/sh $CONFIG_GUESS_PATH/config.guess`
echo "Building for $sys_info"
case "$sys_info" in
*-ibm-aix4* ) OS=AIX ;;
*-freebsd* ) OS=FREEBSD ;;
hppa*-hp-hpux11*) OS=HPUX ;;
*-sgi-irix6* ) OS=IRIX ;;
*-linux* ) OS=LINUX ;;
*-netbsd* ) OS=NETBSD ;;
*-openbsd* ) OS=OPENBSD ;;
*-dec-osf* ) OS=OSF1 ;;
*-solaris2* ) OS=SOLARIS ;;
*-darwin* ) OS=DARWIN ;;
* ) OS=
echo "Sorry, unsupported OS"
exit 1 ;;
esac
echo "Making with OS=$OS"

View file

@ -65,8 +65,6 @@
#endif
#define ST_EVENTSYS_DEFAULT 0
#define ST_EVENTSYS_SELECT 1
#define ST_EVENTSYS_POLL 2
#define ST_EVENTSYS_ALT 3
#ifdef __cplusplus
@ -153,14 +151,6 @@ extern int st_sendto(st_netfd_t fd, const void *msg, int len, const struct socka
extern int st_recvmsg(st_netfd_t fd, struct msghdr *msg, int flags, st_utime_t timeout);
extern int st_sendmsg(st_netfd_t fd, const struct msghdr *msg, int flags, st_utime_t timeout);
// @see http://man7.org/linux/man-pages/man2/sendmmsg.2.html
#include <sys/socket.h>
struct st_mmsghdr {
struct msghdr msg_hdr; /* Message header */
unsigned int msg_len; /* Number of bytes transmitted */
};
extern int st_sendmmsg(st_netfd_t fd, struct st_mmsghdr *msgvec, unsigned int vlen, int flags, st_utime_t timeout);
extern st_netfd_t st_open(const char *path, int oflags, mode_t mode);
#ifdef DEBUG

View file

@ -503,10 +503,15 @@ void _st_del_sleep_q(_st_thread_t *thread)
void _st_vp_check_clock(void)
{
_st_thread_t *thread;
st_utime_t elapsed, now;
st_utime_t now;
#if defined(DEBUG) && defined(DEBUG_STATS)
st_utime_t elapsed;
#endif
now = st_utime();
#if defined(DEBUG) && defined(DEBUG_STATS)
elapsed = now < _ST_LAST_CLOCK? 0 : now - _ST_LAST_CLOCK; // Might step back.
#endif
_ST_LAST_CLOCK = now;
#if defined(DEBUG) && defined(DEBUG_STATS)
@ -620,9 +625,6 @@ _st_thread_t *st_thread_create(void *(*start)(void *arg), void *arg, int joinabl
_st_stack_t *stack;
void **ptds;
char *sp;
#ifdef __ia64__
char *bsp;
#endif
/* Adjust stack size */
if (stk_size == 0)
@ -633,23 +635,7 @@ _st_thread_t *st_thread_create(void *(*start)(void *arg), void *arg, int joinabl
return NULL;
/* Allocate thread object and per-thread data off the stack */
#if defined (MD_STACK_GROWS_DOWN)
sp = stack->stk_top;
#ifdef __ia64__
/*
* The stack segment is split in the middle. The upper half is used
* as backing store for the register stack which grows upward.
* The lower half is used for the traditional memory stack which
* grows downward. Both stacks start in the middle and grow outward
* from each other.
*/
sp -= (stk_size >> 1);
bsp = sp;
/* Make register stack 64-byte aligned */
if ((unsigned long)bsp & 0x3f)
bsp = bsp + (0x40 - ((unsigned long)bsp & 0x3f));
stack->bsp = bsp + _ST_STACK_PAD_SIZE;
#endif
sp = sp - (ST_KEYS_MAX * sizeof(void *));
ptds = (void **) sp;
sp = sp - sizeof(_st_thread_t);
@ -659,21 +645,7 @@ _st_thread_t *st_thread_create(void *(*start)(void *arg), void *arg, int joinabl
if ((unsigned long)sp & 0x3f)
sp = sp - ((unsigned long)sp & 0x3f);
stack->sp = sp - _ST_STACK_PAD_SIZE;
#elif defined (MD_STACK_GROWS_UP)
sp = stack->stk_bottom;
thread = (_st_thread_t *) sp;
sp = sp + sizeof(_st_thread_t);
ptds = (void **) sp;
sp = sp + (ST_KEYS_MAX * sizeof(void *));
/* Make stack 64-byte aligned */
if ((unsigned long)sp & 0x3f)
sp = sp + (0x40 - ((unsigned long)sp & 0x3f));
stack->sp = sp + _ST_STACK_PAD_SIZE;
#else
#error Unknown OS
#endif
memset(thread, 0, sizeof(_st_thread_t));
memset(ptds, 0, ST_KEYS_MAX * sizeof(void *));
@ -683,7 +655,6 @@ _st_thread_t *st_thread_create(void *(*start)(void *arg), void *arg, int joinabl
thread->start = start;
thread->arg = arg;
#ifndef __ia64__
/* Merge from https://github.com/michaeltalyansky/state-threads/commit/cce736426c2320ffec7c9820df49ee7a18ae638c */
#if defined(__arm__) && !defined(MD_USE_BUILTIN_SETJMP) && __GLIBC_MINOR__ >= 19
volatile void * lsp = PTR_MANGLE(stack->sp);
@ -693,9 +664,6 @@ _st_thread_t *st_thread_create(void *(*start)(void *arg), void *arg, int joinabl
#else
_ST_INIT_CONTEXT(thread, stack->sp, _st_thread_main);
#endif
#else
_ST_INIT_CONTEXT(thread, stack->sp, stack->bsp, _st_thread_main);
#endif
/* If thread is joinable, allocate a termination condition variable */
if (joinable) {

View file

@ -1,79 +0,0 @@
Summary: State Threads Library
Name: st
Version: 1.9
Release: 1
Copyright: MPL 1.2 or GPL 2+
Packager: Wesley W. Terpstra <wesley@terpstra.ca>
Source: http://prdownloads.sourceforge.net/state-threads/st-%{version}.tar.gz
Prefix: /usr
BuildRoot: /tmp/%{name}-%{version}-build
Group: Development/Libraries
%description
The State Threads library has an interface similar to POSIX threads.
However, the threads are actually all run in-process. This type of
threading allows for controlled schedualing points. It is highly useful
for designing robust and extremely scalable internet applications since
there is no resource contention and locking is generally unnecessary.
It can be combined with traditional threading or multiple process
parallelism to take advantage of multiple processors.
See: <http://state-threads.sourceforge.net/docs/st.html> for further
information about how state threads improve performance.
%package -n libst-devel
Summary: State Threads Library - Development Files
Group: Development/Libraries
Requires: libst1
%description -n libst-devel
Development headers and documentation for libst
%package -n libst1
Summary: State Threads Library - Shared Libs Major 1
Group: System/Libraries
%description -n libst1
Shared libraries for running applications linked against api version 1.
%prep
%setup -q
%build
make CONFIG_GUESS_PATH=/usr/share/automake default-optimized
%install
if [ -d ${RPM_BUILD_ROOT} ]; then rm -rf ${RPM_BUILD_ROOT}; fi
mkdir -m 0755 -p ${RPM_BUILD_ROOT}/%{prefix}/lib/pkgconfig
mkdir -m 0755 -p ${RPM_BUILD_ROOT}/%{prefix}/include
mkdir -m 0755 -p ${RPM_BUILD_ROOT}/%{prefix}/share/doc/libst-devel
cp -a obj/libst.* ${RPM_BUILD_ROOT}/%{prefix}/lib
cp -a obj/st.h ${RPM_BUILD_ROOT}/%{prefix}/include
sed "s*@prefix@*%{prefix}*g" <st.pc >${RPM_BUILD_ROOT}/%{prefix}/lib/pkgconfig/st.pc
cp -a docs/* ${RPM_BUILD_ROOT}/%{prefix}/share/doc/libst-devel/
cp -a examples ${RPM_BUILD_ROOT}/%{prefix}/share/doc/libst-devel/
%post -n libst1
/sbin/ldconfig %{prefix}/lib
%files -n libst1
%defattr(-,root,root)
%{prefix}/lib/lib*.so.*
%files -n libst-devel
%defattr(-,root,root)
%{prefix}/include/*
%{prefix}/lib/lib*.a
%{prefix}/lib/lib*.so
%{prefix}/lib/pkgconfig/st.pc
%{prefix}/share/doc/libst-devel/*
%clean
if [ -d ${RPM_BUILD_ROOT} ]; then rm -rf ${RPM_BUILD_ROOT}; fi
%changelog
* Wed Dec 26 2001 Wesley W. Terpstra <wesley@terpstra.ca>
- first rpms for libst-1.3.tar.gz

View file

@ -1,61 +1,38 @@
# user must run make the objs/utest dir
# at the same dir of Makefile.
# A sample Makefile for building Google Test and using it in user
# tests. Please tweak it to suit your environment and project. You
# may want to move it to your project's root directory.
#
# SYNOPSIS:
#
# make [all] - makes everything.
# make TARGET - makes the given target.
# make clean - removes all files generated by make.
# Please tweak the following variable definitions as needed by your
# project, except GTEST_HEADERS, which you can use in your own targets
# but shouldn't modify.
# Points to the root of Google Test, relative to where this file is.
# Remember to tweak this if you move this file.
GTEST_DIR = ./gtest
# Flags passed to the preprocessor.
CPPFLAGS += -I$(GTEST_DIR)/include
# The main dir of st.
ST_DIR = ..
# The main dir of st utest.
ST_UTEST = .
# The main dir of gtest.
GTEST_DIR = $(ST_UTEST)/gtest
# Flags passed to the C++ compiler.
CXXFLAGS += -g -O0 -std=c++11
CXXFLAGS += -Wall -Wno-deprecated-declarations -Wno-unused-private-field -Wno-unused-command-line-argument
CXXFLAGS += -DGTEST_USE_OWN_TR1_TUPLE=1
# All tests produced by this Makefile. Remember to add new tests you
# created to the list.
TESTS = ../obj/st_utest
# All Google Test headers. Usually you shouldn't change this
# definition.
GTEST_HEADERS = $(GTEST_DIR)/include/gtest/*.h \
$(GTEST_DIR)/include/gtest/internal/*.h
# Flags for warnings.
WARNFLAGS += -Wall -Wno-deprecated-declarations -Wno-unused-private-field -Wno-unused-command-line-argument
# House-keeping build targets.
all : $(TESTS)
all : $(ST_DIR)/obj/st_utest
clean :
rm -f $(TESTS) gtest.a gtest_main.a *.o *.gcno *.gcda
rm -f $(ST_DIR)/obj/st_utest* $(ST_DIR)/obj/gtest*
# Usually you shouldn't tweak such internal variables, indicated by a
# trailing _.
GTEST_SRCS_ = $(GTEST_DIR)/src/*.cc $(GTEST_DIR)/src/*.h $(GTEST_HEADERS)
GTEST_SRCS_ = $(GTEST_DIR)/src/*.cc $(GTEST_DIR)/src/*.h $(GTEST_DIR)/include/gtest/*.h $(GTEST_DIR)/include/gtest/internal/*.h
# For simplicity and to avoid depending on Google Test's
# implementation details, the dependencies specified below are
# conservative and not optimized. This is fine as Google Test
# compiles fast and for ordinary users its source rarely changes.
../obj/gtest-all.o : $(GTEST_SRCS_)
$(CXX) $(CPPFLAGS) -I$(GTEST_DIR) $(CXXFLAGS) -c \
$(GTEST_DIR)/src/gtest-all.cc -o $@
$(ST_DIR)/obj/gtest-all.o : $(GTEST_SRCS_)
$(CXX) -c $(GTEST_DIR)/src/gtest-all.cc -o $@ \
$(CXXFLAGS) \
$(WARNFLAGS) \
-I$(GTEST_DIR)/include -I$(GTEST_DIR)
../obj/gtest.a : ../obj/gtest-all.o
$(ST_DIR)/obj/gtest.a : $(ST_DIR)/obj/gtest-all.o
$(AR) $(ARFLAGS) $@ $^
#####################################################################################
@ -64,19 +41,20 @@ GTEST_SRCS_ = $(GTEST_DIR)/src/*.cc $(GTEST_DIR)/src/*.h $(GTEST_HEADERS)
#####################################################################################
#####################################################################################
# Includes, the include dir.
ST_UTEST_INC = -I../obj -I./
# Depends, the depends objects
ST_UTEST_DEPS = ../obj/libst.a
ST_UTEST_DEPS = $(ST_DIR)/obj/libst.a
# Depends, utest header files
UTEST_DEPS = st_utest.hpp
UTEST_DEPS = $(ST_UTEST)/st_utest.hpp
# Objects, build each object of utest
../obj/st_utest.o : st_utest.cpp $(ST_UTEST_DEPS) $(UTEST_DEPS)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(UTEST_FLAGS) $(ST_UTEST_INC) -c st_utest.cpp -o $@
$(ST_DIR)/obj/st_utest.o : st_utest.cpp $(ST_UTEST_DEPS) $(UTEST_DEPS)
$(CXX) -c st_utest.cpp -o $@ \
$(CXXFLAGS) $(UTEST_FLAGS) \
$(WARNFLAGS) \
-I$(GTEST_DIR)/include -I$(ST_UTEST) -I$(ST_DIR) -I$(ST_DIR)/obj
# generate the utest binary
../obj/st_utest : ../obj/st_utest.o ../obj/gtest.a $(ST_UTEST_DEPS)
$(CXX) -o $@ $(CPPFLAGS) $(CXXFLAGS) $(UTEST_FLAGS) $^ -lpthread -ldl
$(ST_DIR)/obj/st_utest : $(ST_DIR)/obj/st_utest.o $(ST_DIR)/obj/gtest.a $(ST_UTEST_DEPS)
$(CXX) -o $@ $(CXXFLAGS) $(UTEST_FLAGS) \
-lpthread -ldl $^

View file

@ -391,24 +391,34 @@ fi
# state-threads
#####################################################################################
# check the cross build flag file, if flag changed, need to rebuild the st.
_ST_MAKE=linux-debug && _ST_EXTRA_CFLAGS="-O0" && _ST_LD=${SRS_TOOL_LD} && _ST_OBJ="LINUX_`uname -r`_DBG"
_ST_MAKE=linux-debug && _ST_LD=${SRS_TOOL_LD} && _ST_OBJ="LINUX_`uname -r`_DBG"
# Always alloc on heap, @see https://github.com/ossrs/srs/issues/509#issuecomment-719931676
_ST_EXTRA_CFLAGS="-DMALLOC_STACK"
# For valgrind to detect memory issues.
if [[ $SRS_VALGRIND == YES ]]; then
_ST_EXTRA_CFLAGS="$_ST_EXTRA_CFLAGS -DMD_VALGRIND"
fi
# for osx, use darwin for st, donot use epoll.
if [[ $SRS_OSX == YES ]]; then
_ST_MAKE=darwin-debug && _ST_EXTRA_CFLAGS="-DMD_HAVE_KQUEUE" && _ST_LD=${SRS_TOOL_CC} && _ST_OBJ="DARWIN_`uname -r`_DBG"
_ST_MAKE=darwin-debug && _ST_LD=${SRS_TOOL_CC} && _ST_OBJ="DARWIN_`uname -r`_DBG"
fi
# Whether enable debug stats.
if [[ $SRS_DEBUG_STATS == YES ]]; then
_ST_EXTRA_CFLAGS="$_ST_EXTRA_CFLAGS -DDEBUG_STATS"
fi
# Always alloc on heap, @see https://github.com/ossrs/srs/issues/509#issuecomment-719931676
_ST_EXTRA_CFLAGS="$_ST_EXTRA_CFLAGS -DMALLOC_STACK"
# Pass the global extra flags.
if [[ $SRS_EXTRA_FLAGS != '' ]]; then
_ST_EXTRA_CFLAGS="$_ST_EXTRA_CFLAGS $SRS_EXTRA_FLAGS"
fi
# Whether link as .so
if [[ $SRS_SHARED_ST == YES ]]; then
_ST_STATIC_ONLY=no;
else
_ST_STATIC_ONLY=yes;
fi
# The final args to make st.
_ST_MAKE_ARGS="${_ST_MAKE} STATIC_ONLY=${_ST_STATIC_ONLY}"
_ST_MAKE_ARGS="${_ST_MAKE_ARGS} CC=${SRS_TOOL_CC} AR=${SRS_TOOL_AR} LD=${_ST_LD} RANDLIB=${SRS_TOOL_RANDLIB}"
# Patched ST from https://github.com/ossrs/state-threads/tree/srs
if [[ -f ${SRS_OBJS}/${SRS_PLATFORM}/st-srs/${_ST_OBJ}/libst.a ]]; then
echo "The state-threads is ok.";
@ -420,19 +430,8 @@ else
cd ${SRS_OBJS}/${SRS_PLATFORM}/st-srs && ln -sf ../../../3rdparty/st-srs .src &&
# Link source files under .src
_srs_link_file .src/ ./ ./ &&
for dir in `(cd .src && find . -maxdepth 1 -type d|grep '\./')`; do
dir=`basename $dir` && mkdir -p $dir && _srs_link_file .src/$dir/ $dir/ ../
done &&
# Link source files under .src/xxx, the first child dir.
for dir in `(cd .src && find . -maxdepth 1 -type d|grep '\./'|grep -v Linux|grep -v Darwin)`; do
mkdir -p $dir &&
for file in `(cd .src/$dir && find . -maxdepth 1 -type f ! -name '*.o' ! -name '*.d')`; do
ln -sf ../.src/$dir/$file $dir/$file;
done;
done &&
# Build source code.
make ${_ST_MAKE} EXTRA_CFLAGS="${_ST_EXTRA_CFLAGS}" \
CC=${SRS_TOOL_CC} AR=${SRS_TOOL_AR} LD=${_ST_LD} RANDLIB=${SRS_TOOL_RANDLIB} &&
env EXTRA_CFLAGS="${_ST_EXTRA_CFLAGS}" make ${_ST_MAKE_ARGS} &&
cd .. && rm -rf st && ln -sf st-srs/${_ST_OBJ} st
)
fi

5
trunk/configure vendored
View file

@ -132,7 +132,7 @@ END
#
# st(state-threads) the basic network library for SRS.
LibSTRoot="${SRS_OBJS_DIR}/st"; LibSTfile="${LibSTRoot}/libst.a"
if [[ $SRS_SHARED_ST == YES ]]; then LibSTfile="-lst"; fi
if [[ $SRS_SHARED_ST == YES ]]; then LibSTfile="-L${LibSTRoot} -lst"; fi
# srtp
if [[ $SRS_RTC == YES ]]; then
@ -546,7 +546,8 @@ clean_st:
st:
(cd ${SRS_OBJS_DIR} && rm -f srs srs_utest)
(cd ${SRS_OBJS_DIR}/${SRS_PLATFORM}/st-srs && \$(MAKE) clean && \$(MAKE) ${_ST_MAKE} EXTRA_CFLAGS="${_ST_EXTRA_CFLAGS}")
(cd ${SRS_OBJS_DIR}/${SRS_PLATFORM}/st-srs && \$(MAKE) clean)
(cd ${SRS_OBJS_DIR}/${SRS_PLATFORM}/st-srs && env EXTRA_CFLAGS="${_ST_EXTRA_CFLAGS}" \$(MAKE) ${_ST_MAKE_ARGS})
@echo "Please rebuild srs by: rm -f objs/srs && make"
ffmpeg:

View file

@ -279,6 +279,8 @@ int main(int argc, char** argv)
memcpy(&p->msg_hdr, &msg, sizeof(msghdr));
p->msg_len = 0;
}
// The sendmmsg is removed by https://github.com/ossrs/srs/commit/34dae0fe0ddf2e95353ca8cbdc799f4abf96aead
if (zerocopy) {
r0 = st_sendmmsg(stfd, hdrs, nn_copies + 1, MSG_ZEROCOPY, ST_UTIME_NO_TIMEOUT);
} else {

View file

@ -26,6 +26,6 @@
#define VERSION_MAJOR 5
#define VERSION_MINOR 0
#define VERSION_REVISION 1
#define VERSION_REVISION 2
#endif