mirror of
https://github.com/ossrs/srs.git
synced 2025-03-09 15:49:59 +00:00
rename st-1.9 to st
This commit is contained in:
parent
7692373e02
commit
2f388d614f
14 changed files with 0 additions and 0 deletions
469
trunk/research/st/Makefile
Normal file
469
trunk/research/st/Makefile
Normal file
|
@ -0,0 +1,469 @@
|
|||
# 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 Netscape Portable Runtime library.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Netscape
|
||||
# Communications Corporation. Portions created by Netscape are
|
||||
# Copyright (C) 1994-2000 Netscape Communications Corporation. All
|
||||
# Rights Reserved.
|
||||
#
|
||||
# Contributor(s): Silicon Graphics, Inc.
|
||||
#
|
||||
# Portions created by SGI are Copyright (C) 2000-2001 Silicon
|
||||
# Graphics, Inc. All Rights Reserved.
|
||||
#
|
||||
# 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 is the full version of the libst library - modify carefully
|
||||
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.
|
||||
##########################
|
||||
|
||||
CC = cc
|
||||
AR = ar
|
||||
LD = ld
|
||||
RANLIB = ranlib
|
||||
LN = ln
|
||||
|
||||
SHELL = /bin/sh
|
||||
ECHO = /bin/echo
|
||||
|
||||
BUILD = DBG
|
||||
TARGETDIR = $(OS)_$(shell uname -r)_$(BUILD)
|
||||
|
||||
DEFINES = -D$(OS)
|
||||
CFLAGS =
|
||||
SFLAGS =
|
||||
ARFLAGS = -rv
|
||||
LNFLAGS = -s
|
||||
DSO_SUFFIX = so
|
||||
|
||||
MAJOR = $(shell echo $(VERSION) | sed 's/^\([^\.]*\).*/\1/')
|
||||
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
|
||||
|
||||
#
|
||||
# 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)
|
||||
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 i386 -arch x86_64
|
||||
LDFLAGS += -arch i386 -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
|
||||
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.
|
||||
##########################
|
||||
|
||||
|
||||
ifeq ($(BUILD), OPT)
|
||||
OTHER_FLAGS += -O
|
||||
else
|
||||
OTHER_FLAGS += -g
|
||||
DEFINES += -DDEBUG
|
||||
endif
|
||||
|
||||
##########################
|
||||
# Other possible defines:
|
||||
# To use poll(2) instead of select(2) for events checking:
|
||||
# DEFINES += -DUSE_POLL
|
||||
# You may prefer to use select for applications that have many threads
|
||||
# using one file descriptor, and poll for applications that have many
|
||||
# different file descriptors. With USE_POLL poll() is called with at
|
||||
# least one pollfd per I/O-blocked thread, so 1000 threads sharing one
|
||||
# descriptor will poll 1000 identical pollfds and select would be more
|
||||
# efficient. But if the threads all use different descriptors poll()
|
||||
# may be better depending on your operating system's implementation of
|
||||
# poll and select. Really, it's up to you. Oh, and on some platforms
|
||||
# poll() fails with more than a few dozen descriptors.
|
||||
#
|
||||
# Some platforms allow to define FD_SETSIZE (if select() is used), e.g.:
|
||||
# DEFINES += -DFD_SETSIZE=4096
|
||||
#
|
||||
# To use malloc(3) instead of mmap(2) for stack allocation:
|
||||
# DEFINES += -DMALLOC_STACK
|
||||
#
|
||||
# To provision more than the default 16 thread-specific-data keys
|
||||
# (but not too many!):
|
||||
# DEFINES += -DST_KEYS_MAX=<n>
|
||||
#
|
||||
# To start with more than the default 64 initial pollfd slots
|
||||
# (but the table grows dynamically anyway):
|
||||
# DEFINES += -DST_MIN_POLLFDS_SIZE=<n>
|
||||
#
|
||||
# Note that you can also add these defines by specifying them as
|
||||
# make/gmake arguments (without editing this Makefile). For example:
|
||||
#
|
||||
# make EXTRA_CFLAGS=-DUSE_POLL <target>
|
||||
#
|
||||
# (replace make with gmake if needed).
|
||||
#
|
||||
# You can also modify the default selection of an alternative event
|
||||
# notification mechanism. E.g., to enable kqueue(2) support (if it's not
|
||||
# enabled by default):
|
||||
#
|
||||
# gmake EXTRA_CFLAGS=-DMD_HAVE_KQUEUE <target>
|
||||
#
|
||||
# or to disable default epoll(4) support:
|
||||
#
|
||||
# make EXTRA_CFLAGS=-UMD_HAVE_EPOLL <target>
|
||||
#
|
||||
##########################
|
||||
|
||||
CFLAGS += $(DEFINES) $(OTHER_FLAGS) $(EXTRA_CFLAGS)
|
||||
|
||||
OBJS = $(TARGETDIR)/sched.o \
|
||||
$(TARGETDIR)/stk.o \
|
||||
$(TARGETDIR)/sync.o \
|
||||
$(TARGETDIR)/key.o \
|
||||
$(TARGETDIR)/io.o \
|
||||
$(TARGETDIR)/event.o
|
||||
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
|
||||
|
||||
ifeq ($(OS), DARWIN)
|
||||
LINKNAME = libst.$(DSO_SUFFIX)
|
||||
SONAME = libst.$(MAJOR).$(DSO_SUFFIX)
|
||||
FULLNAME = libst.$(VERSION).$(DSO_SUFFIX)
|
||||
endif
|
||||
|
||||
ifeq ($(STATIC_ONLY), yes)
|
||||
LIBRARIES = $(SLIBRARY)
|
||||
else
|
||||
LIBRARIES = $(SLIBRARY) $(DLIBRARY)
|
||||
endif
|
||||
|
||||
ifeq ($(OS),)
|
||||
ST_ALL = unknown
|
||||
else
|
||||
ST_ALL = $(TARGETDIR) $(LIBRARIES) $(HEADER) $(EXAMPLES) $(DESC)
|
||||
endif
|
||||
|
||||
all: $(ST_ALL)
|
||||
|
||||
unknown:
|
||||
@echo
|
||||
@echo "Please specify one of the following targets:"
|
||||
@echo
|
||||
@for target in $(TARGETS); do echo $$target; done
|
||||
@echo
|
||||
|
||||
st.pc: st.pc.in
|
||||
sed "s/@VERSION@/${VERSION}/g" < $< > $@
|
||||
|
||||
$(TARGETDIR):
|
||||
if [ ! -d $(TARGETDIR) ]; then mkdir $(TARGETDIR); fi
|
||||
|
||||
$(SLIBRARY): $(OBJS)
|
||||
$(AR) $(ARFLAGS) $@ $(OBJS)
|
||||
$(RANLIB) $@
|
||||
rm -f obj; $(LN) $(LNFLAGS) $(TARGETDIR) obj
|
||||
|
||||
$(DLIBRARY): $(OBJS:%.o=%-pic.o)
|
||||
$(LD) $(LDFLAGS) $^ -o $@
|
||||
if test "$(LINKNAME)"; then \
|
||||
cd $(TARGETDIR); \
|
||||
rm -f $(SONAME) $(LINKNAME); \
|
||||
$(LN) $(LNFLAGS) $(FULLNAME) $(SONAME); \
|
||||
$(LN) $(LNFLAGS) $(FULLNAME) $(LINKNAME); \
|
||||
fi
|
||||
|
||||
$(HEADER): public.h
|
||||
rm -f $@
|
||||
cp public.h $@
|
||||
|
||||
$(TARGETDIR)/md.o: md.S
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
$(TARGETDIR)/%.o: %.c common.h md.h
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
examples::
|
||||
@echo Making $@
|
||||
@cd $@; $(MAKE) CC="$(CC)" CFLAGS="$(CFLAGS)" OS="$(OS)" TARGETDIR="$(TARGETDIR)"
|
||||
|
||||
clean:
|
||||
rm -rf *_OPT *_DBG obj st.pc
|
||||
|
||||
##########################
|
||||
# Pattern rules:
|
||||
|
||||
ifneq ($(SFLAGS),)
|
||||
# Compile with shared library options if it's a C file
|
||||
$(TARGETDIR)/%-pic.o: %.c common.h md.h
|
||||
$(CC) $(CFLAGS) $(SFLAGS) -c $< -o $@
|
||||
endif
|
||||
|
||||
# Compile assembly as normal or C as normal if no SFLAGS
|
||||
%-pic.o: %.o
|
||||
rm -f $@; $(LN) $(LNFLAGS) $(<F) $@
|
||||
|
||||
##########################
|
||||
# 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"
|
||||
|
||||
##########################
|
||||
|
466
trunk/research/st/common.h
Normal file
466
trunk/research/st/common.h
Normal file
|
@ -0,0 +1,466 @@
|
|||
/*
|
||||
* 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 Netscape Portable Runtime library.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1994-2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Silicon Graphics, Inc.
|
||||
*
|
||||
* Portions created by SGI are Copyright (C) 2000-2001 Silicon
|
||||
* Graphics, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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 is derived directly from Netscape Communications Corporation,
|
||||
* and consists of extensive modifications made during the year(s) 1999-2000.
|
||||
*/
|
||||
|
||||
#ifndef __ST_COMMON_H__
|
||||
#define __ST_COMMON_H__
|
||||
|
||||
#include <stddef.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
/* Enable assertions only if DEBUG is defined */
|
||||
#ifndef DEBUG
|
||||
#define NDEBUG
|
||||
#endif
|
||||
#include <assert.h>
|
||||
#define ST_ASSERT(expr) assert(expr)
|
||||
|
||||
#define ST_BEGIN_MACRO {
|
||||
#define ST_END_MACRO }
|
||||
|
||||
#ifdef DEBUG
|
||||
#define ST_HIDDEN /*nothing*/
|
||||
#else
|
||||
#define ST_HIDDEN static
|
||||
#endif
|
||||
|
||||
#include "public.h"
|
||||
#include "md.h"
|
||||
|
||||
|
||||
/*****************************************
|
||||
* Circular linked list definitions
|
||||
*/
|
||||
|
||||
typedef struct _st_clist {
|
||||
struct _st_clist *next;
|
||||
struct _st_clist *prev;
|
||||
} _st_clist_t;
|
||||
|
||||
/* Insert element "_e" into the list, before "_l" */
|
||||
#define ST_INSERT_BEFORE(_e,_l) \
|
||||
ST_BEGIN_MACRO \
|
||||
(_e)->next = (_l); \
|
||||
(_e)->prev = (_l)->prev; \
|
||||
(_l)->prev->next = (_e); \
|
||||
(_l)->prev = (_e); \
|
||||
ST_END_MACRO
|
||||
|
||||
/* Insert element "_e" into the list, after "_l" */
|
||||
#define ST_INSERT_AFTER(_e,_l) \
|
||||
ST_BEGIN_MACRO \
|
||||
(_e)->next = (_l)->next; \
|
||||
(_e)->prev = (_l); \
|
||||
(_l)->next->prev = (_e); \
|
||||
(_l)->next = (_e); \
|
||||
ST_END_MACRO
|
||||
|
||||
/* Return the element following element "_e" */
|
||||
#define ST_NEXT_LINK(_e) ((_e)->next)
|
||||
|
||||
/* Append an element "_e" to the end of the list "_l" */
|
||||
#define ST_APPEND_LINK(_e,_l) ST_INSERT_BEFORE(_e,_l)
|
||||
|
||||
/* Insert an element "_e" at the head of the list "_l" */
|
||||
#define ST_INSERT_LINK(_e,_l) ST_INSERT_AFTER(_e,_l)
|
||||
|
||||
/* Return the head/tail of the list */
|
||||
#define ST_LIST_HEAD(_l) (_l)->next
|
||||
#define ST_LIST_TAIL(_l) (_l)->prev
|
||||
|
||||
/* Remove the element "_e" from it's circular list */
|
||||
#define ST_REMOVE_LINK(_e) \
|
||||
ST_BEGIN_MACRO \
|
||||
(_e)->prev->next = (_e)->next; \
|
||||
(_e)->next->prev = (_e)->prev; \
|
||||
ST_END_MACRO
|
||||
|
||||
/* Return non-zero if the given circular list "_l" is empty, */
|
||||
/* zero if the circular list is not empty */
|
||||
#define ST_CLIST_IS_EMPTY(_l) \
|
||||
((_l)->next == (_l))
|
||||
|
||||
/* Initialize a circular list */
|
||||
#define ST_INIT_CLIST(_l) \
|
||||
ST_BEGIN_MACRO \
|
||||
(_l)->next = (_l); \
|
||||
(_l)->prev = (_l); \
|
||||
ST_END_MACRO
|
||||
|
||||
#define ST_INIT_STATIC_CLIST(_l) \
|
||||
{(_l), (_l)}
|
||||
|
||||
|
||||
/*****************************************
|
||||
* Basic types definitions
|
||||
*/
|
||||
|
||||
typedef void (*_st_destructor_t)(void *);
|
||||
|
||||
|
||||
typedef struct _st_stack {
|
||||
_st_clist_t links;
|
||||
char *vaddr; /* Base of stack's allocated memory */
|
||||
int vaddr_size; /* Size of stack's allocated memory */
|
||||
int stk_size; /* Size of usable portion of the 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
|
||||
} _st_stack_t;
|
||||
|
||||
|
||||
typedef struct _st_cond {
|
||||
_st_clist_t wait_q; /* Condition variable wait queue */
|
||||
} _st_cond_t;
|
||||
|
||||
|
||||
typedef struct _st_thread _st_thread_t;
|
||||
|
||||
struct _st_thread {
|
||||
int state; /* Thread's state */
|
||||
int flags; /* Thread's flags */
|
||||
|
||||
void *(*start)(void *arg); /* The start function of the thread */
|
||||
void *arg; /* Argument of the start function */
|
||||
void *retval; /* Return value of the start function */
|
||||
|
||||
_st_stack_t *stack; /* Info about thread's stack */
|
||||
|
||||
_st_clist_t links; /* For putting on run/sleep/zombie queue */
|
||||
_st_clist_t wait_links; /* For putting on mutex/condvar wait queue */
|
||||
#ifdef DEBUG
|
||||
_st_clist_t tlink; /* For putting on thread queue */
|
||||
#endif
|
||||
|
||||
st_utime_t due; /* Wakeup time when thread is sleeping */
|
||||
_st_thread_t *left; /* For putting in timeout heap */
|
||||
_st_thread_t *right; /* -- see docs/timeout_heap.txt for details */
|
||||
int heap_index;
|
||||
|
||||
void **private_data; /* Per thread private data */
|
||||
|
||||
_st_cond_t *term; /* Termination condition variable for join */
|
||||
|
||||
jmp_buf context; /* Thread's context */
|
||||
};
|
||||
|
||||
|
||||
typedef struct _st_mutex {
|
||||
_st_thread_t *owner; /* Current mutex owner */
|
||||
_st_clist_t wait_q; /* Mutex wait queue */
|
||||
} _st_mutex_t;
|
||||
|
||||
|
||||
typedef struct _st_pollq {
|
||||
_st_clist_t links; /* For putting on io queue */
|
||||
_st_thread_t *thread; /* Polling thread */
|
||||
struct pollfd *pds; /* Array of poll descriptors */
|
||||
int npds; /* Length of the array */
|
||||
int on_ioq; /* Is it on ioq? */
|
||||
} _st_pollq_t;
|
||||
|
||||
|
||||
typedef struct _st_eventsys_ops {
|
||||
const char *name; /* Name of this event system */
|
||||
int val; /* Type of this event system */
|
||||
int (*init)(void); /* Initialization */
|
||||
void (*dispatch)(void); /* Dispatch function */
|
||||
int (*pollset_add)(struct pollfd *, int); /* Add descriptor set */
|
||||
void (*pollset_del)(struct pollfd *, int); /* Delete descriptor set */
|
||||
int (*fd_new)(int); /* New descriptor allocated */
|
||||
int (*fd_close)(int); /* Descriptor closed */
|
||||
int (*fd_getlimit)(void); /* Descriptor hard limit */
|
||||
} _st_eventsys_t;
|
||||
|
||||
|
||||
typedef struct _st_vp {
|
||||
_st_thread_t *idle_thread; /* Idle thread for this vp */
|
||||
st_utime_t last_clock; /* The last time we went into vp_check_clock() */
|
||||
|
||||
_st_clist_t run_q; /* run queue for this vp */
|
||||
_st_clist_t io_q; /* io queue for this vp */
|
||||
_st_clist_t zombie_q; /* zombie queue for this vp */
|
||||
#ifdef DEBUG
|
||||
_st_clist_t thread_q; /* all threads of this vp */
|
||||
#endif
|
||||
int pagesize;
|
||||
|
||||
_st_thread_t *sleep_q; /* sleep queue for this vp */
|
||||
int sleepq_size; /* number of threads on sleep queue */
|
||||
|
||||
#ifdef ST_SWITCH_CB
|
||||
st_switch_cb_t switch_out_cb; /* called when a thread is switched out */
|
||||
st_switch_cb_t switch_in_cb; /* called when a thread is switched in */
|
||||
#endif
|
||||
} _st_vp_t;
|
||||
|
||||
|
||||
typedef struct _st_netfd {
|
||||
int osfd; /* Underlying OS file descriptor */
|
||||
int inuse; /* In-use flag */
|
||||
void *private_data; /* Per descriptor private data */
|
||||
_st_destructor_t destructor; /* Private data destructor function */
|
||||
void *aux_data; /* Auxiliary data for internal use */
|
||||
struct _st_netfd *next; /* For putting on the free list */
|
||||
} _st_netfd_t;
|
||||
|
||||
|
||||
/*****************************************
|
||||
* Current vp, thread, and event system
|
||||
*/
|
||||
|
||||
extern _st_vp_t _st_this_vp;
|
||||
extern _st_thread_t *_st_this_thread;
|
||||
extern _st_eventsys_t *_st_eventsys;
|
||||
|
||||
#define _ST_CURRENT_THREAD() (_st_this_thread)
|
||||
#define _ST_SET_CURRENT_THREAD(_thread) (_st_this_thread = (_thread))
|
||||
|
||||
#define _ST_LAST_CLOCK (_st_this_vp.last_clock)
|
||||
|
||||
#define _ST_RUNQ (_st_this_vp.run_q)
|
||||
#define _ST_IOQ (_st_this_vp.io_q)
|
||||
#define _ST_ZOMBIEQ (_st_this_vp.zombie_q)
|
||||
#ifdef DEBUG
|
||||
#define _ST_THREADQ (_st_this_vp.thread_q)
|
||||
#endif
|
||||
|
||||
#define _ST_PAGE_SIZE (_st_this_vp.pagesize)
|
||||
|
||||
#define _ST_SLEEPQ (_st_this_vp.sleep_q)
|
||||
#define _ST_SLEEPQ_SIZE (_st_this_vp.sleepq_size)
|
||||
|
||||
#define _ST_VP_IDLE() (*_st_eventsys->dispatch)()
|
||||
|
||||
|
||||
/*****************************************
|
||||
* vp queues operations
|
||||
*/
|
||||
|
||||
#define _ST_ADD_IOQ(_pq) ST_APPEND_LINK(&_pq.links, &_ST_IOQ)
|
||||
#define _ST_DEL_IOQ(_pq) ST_REMOVE_LINK(&_pq.links)
|
||||
|
||||
#define _ST_ADD_RUNQ(_thr) ST_APPEND_LINK(&(_thr)->links, &_ST_RUNQ)
|
||||
#define _ST_DEL_RUNQ(_thr) ST_REMOVE_LINK(&(_thr)->links)
|
||||
|
||||
#define _ST_ADD_SLEEPQ(_thr, _timeout) _st_add_sleep_q(_thr, _timeout)
|
||||
#define _ST_DEL_SLEEPQ(_thr) _st_del_sleep_q(_thr)
|
||||
|
||||
#define _ST_ADD_ZOMBIEQ(_thr) ST_APPEND_LINK(&(_thr)->links, &_ST_ZOMBIEQ)
|
||||
#define _ST_DEL_ZOMBIEQ(_thr) ST_REMOVE_LINK(&(_thr)->links)
|
||||
|
||||
#ifdef DEBUG
|
||||
#define _ST_ADD_THREADQ(_thr) ST_APPEND_LINK(&(_thr)->tlink, &_ST_THREADQ)
|
||||
#define _ST_DEL_THREADQ(_thr) ST_REMOVE_LINK(&(_thr)->tlink)
|
||||
#endif
|
||||
|
||||
|
||||
/*****************************************
|
||||
* Thread states and flags
|
||||
*/
|
||||
|
||||
#define _ST_ST_RUNNING 0
|
||||
#define _ST_ST_RUNNABLE 1
|
||||
#define _ST_ST_IO_WAIT 2
|
||||
#define _ST_ST_LOCK_WAIT 3
|
||||
#define _ST_ST_COND_WAIT 4
|
||||
#define _ST_ST_SLEEPING 5
|
||||
#define _ST_ST_ZOMBIE 6
|
||||
#define _ST_ST_SUSPENDED 7
|
||||
|
||||
#define _ST_FL_PRIMORDIAL 0x01
|
||||
#define _ST_FL_IDLE_THREAD 0x02
|
||||
#define _ST_FL_ON_SLEEPQ 0x04
|
||||
#define _ST_FL_INTERRUPT 0x08
|
||||
#define _ST_FL_TIMEDOUT 0x10
|
||||
|
||||
|
||||
/*****************************************
|
||||
* Pointer conversion
|
||||
*/
|
||||
|
||||
#ifndef offsetof
|
||||
#define offsetof(type, identifier) ((size_t)&(((type *)0)->identifier))
|
||||
#endif
|
||||
|
||||
#define _ST_THREAD_PTR(_qp) \
|
||||
((_st_thread_t *)((char *)(_qp) - offsetof(_st_thread_t, links)))
|
||||
|
||||
#define _ST_THREAD_WAITQ_PTR(_qp) \
|
||||
((_st_thread_t *)((char *)(_qp) - offsetof(_st_thread_t, wait_links)))
|
||||
|
||||
#define _ST_THREAD_STACK_PTR(_qp) \
|
||||
((_st_stack_t *)((char*)(_qp) - offsetof(_st_stack_t, links)))
|
||||
|
||||
#define _ST_POLLQUEUE_PTR(_qp) \
|
||||
((_st_pollq_t *)((char *)(_qp) - offsetof(_st_pollq_t, links)))
|
||||
|
||||
#ifdef DEBUG
|
||||
#define _ST_THREAD_THREADQ_PTR(_qp) \
|
||||
((_st_thread_t *)((char *)(_qp) - offsetof(_st_thread_t, tlink)))
|
||||
#endif
|
||||
|
||||
|
||||
/*****************************************
|
||||
* Constants
|
||||
*/
|
||||
|
||||
#ifndef ST_UTIME_NO_TIMEOUT
|
||||
#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
|
||||
|
||||
#ifndef ST_KEYS_MAX
|
||||
#define ST_KEYS_MAX 16
|
||||
#endif
|
||||
|
||||
#ifndef ST_MIN_POLLFDS_SIZE
|
||||
#define ST_MIN_POLLFDS_SIZE 64
|
||||
#endif
|
||||
|
||||
|
||||
/*****************************************
|
||||
* Threads context switching
|
||||
*/
|
||||
|
||||
#ifdef DEBUG
|
||||
void _st_iterate_threads(void);
|
||||
#define ST_DEBUG_ITERATE_THREADS() _st_iterate_threads()
|
||||
#else
|
||||
#define ST_DEBUG_ITERATE_THREADS()
|
||||
#endif
|
||||
|
||||
#ifdef ST_SWITCH_CB
|
||||
#define ST_SWITCH_OUT_CB(_thread) \
|
||||
if (_st_this_vp.switch_out_cb != NULL && \
|
||||
_thread != _st_this_vp.idle_thread && \
|
||||
_thread->state != _ST_ST_ZOMBIE) { \
|
||||
_st_this_vp.switch_out_cb(); \
|
||||
}
|
||||
#define ST_SWITCH_IN_CB(_thread) \
|
||||
if (_st_this_vp.switch_in_cb != NULL && \
|
||||
_thread != _st_this_vp.idle_thread && \
|
||||
_thread->state != _ST_ST_ZOMBIE) { \
|
||||
_st_this_vp.switch_in_cb(); \
|
||||
}
|
||||
#else
|
||||
#define ST_SWITCH_OUT_CB(_thread)
|
||||
#define ST_SWITCH_IN_CB(_thread)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Switch away from the current thread context by saving its state and
|
||||
* calling the thread scheduler
|
||||
*/
|
||||
#define _ST_SWITCH_CONTEXT(_thread) \
|
||||
ST_BEGIN_MACRO \
|
||||
ST_SWITCH_OUT_CB(_thread); \
|
||||
if (!MD_SETJMP((_thread)->context)) { \
|
||||
_st_vp_schedule(); \
|
||||
} \
|
||||
ST_DEBUG_ITERATE_THREADS(); \
|
||||
ST_SWITCH_IN_CB(_thread); \
|
||||
ST_END_MACRO
|
||||
|
||||
/*
|
||||
* Restore a thread context that was saved by _ST_SWITCH_CONTEXT or
|
||||
* initialized by _ST_INIT_CONTEXT
|
||||
*/
|
||||
#define _ST_RESTORE_CONTEXT(_thread) \
|
||||
ST_BEGIN_MACRO \
|
||||
_ST_SET_CURRENT_THREAD(_thread); \
|
||||
MD_LONGJMP((_thread)->context, 1); \
|
||||
ST_END_MACRO
|
||||
|
||||
/*
|
||||
* Initialize the thread context preparing it to execute _main
|
||||
*/
|
||||
#ifdef MD_INIT_CONTEXT
|
||||
#define _ST_INIT_CONTEXT MD_INIT_CONTEXT
|
||||
#else
|
||||
#error Unknown OS
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Number of bytes reserved under the stack "bottom"
|
||||
*/
|
||||
#define _ST_STACK_PAD_SIZE MD_STACK_PAD_SIZE
|
||||
|
||||
|
||||
/*****************************************
|
||||
* Forward declarations
|
||||
*/
|
||||
|
||||
void _st_vp_schedule(void);
|
||||
void _st_vp_check_clock(void);
|
||||
void *_st_idle_thread_start(void *arg);
|
||||
void _st_thread_main(void);
|
||||
void _st_thread_cleanup(_st_thread_t *thread);
|
||||
void _st_add_sleep_q(_st_thread_t *thread, st_utime_t timeout);
|
||||
void _st_del_sleep_q(_st_thread_t *thread);
|
||||
_st_stack_t *_st_stack_new(int stack_size);
|
||||
void _st_stack_free(_st_stack_t *ts);
|
||||
int _st_io_init(void);
|
||||
|
||||
st_utime_t st_utime(void);
|
||||
_st_cond_t *st_cond_new(void);
|
||||
int st_cond_destroy(_st_cond_t *cvar);
|
||||
int st_cond_timedwait(_st_cond_t *cvar, st_utime_t timeout);
|
||||
int st_cond_signal(_st_cond_t *cvar);
|
||||
ssize_t st_read(_st_netfd_t *fd, void *buf, size_t nbyte, st_utime_t timeout);
|
||||
ssize_t st_write(_st_netfd_t *fd, const void *buf, size_t nbyte,
|
||||
st_utime_t timeout);
|
||||
int st_poll(struct pollfd *pds, int npds, st_utime_t timeout);
|
||||
_st_thread_t *st_thread_create(void *(*start)(void *arg), void *arg,
|
||||
int joinable, int stk_size);
|
||||
|
||||
#endif /* !__ST_COMMON_H__ */
|
||||
|
1449
trunk/research/st/event.c
Normal file
1449
trunk/research/st/event.c
Normal file
File diff suppressed because it is too large
Load diff
778
trunk/research/st/io.c
Normal file
778
trunk/research/st/io.c
Normal file
|
@ -0,0 +1,778 @@
|
|||
/*
|
||||
* 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 Netscape Portable Runtime library.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1994-2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Silicon Graphics, Inc.
|
||||
*
|
||||
* Portions created by SGI are Copyright (C) 2000-2001 Silicon
|
||||
* Graphics, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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 is derived directly from Netscape Communications Corporation,
|
||||
* and consists of extensive modifications made during the year(s) 1999-2000.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include "common.h"
|
||||
|
||||
|
||||
#if EAGAIN != EWOULDBLOCK
|
||||
#define _IO_NOT_READY_ERROR ((errno == EAGAIN) || (errno == EWOULDBLOCK))
|
||||
#else
|
||||
#define _IO_NOT_READY_ERROR (errno == EAGAIN)
|
||||
#endif
|
||||
|
||||
#define _LOCAL_MAXIOV 16
|
||||
|
||||
/* File descriptor object free list */
|
||||
static _st_netfd_t *_st_netfd_freelist = NULL;
|
||||
/* Maximum number of file descriptors that the process can open */
|
||||
static int _st_osfd_limit = -1;
|
||||
|
||||
static void _st_netfd_free_aux_data(_st_netfd_t *fd);
|
||||
|
||||
int _st_io_init(void)
|
||||
{
|
||||
struct sigaction sigact;
|
||||
struct rlimit rlim;
|
||||
int fdlim;
|
||||
|
||||
/* Ignore SIGPIPE */
|
||||
sigact.sa_handler = SIG_IGN;
|
||||
sigemptyset(&sigact.sa_mask);
|
||||
sigact.sa_flags = 0;
|
||||
if (sigaction(SIGPIPE, &sigact, NULL) < 0)
|
||||
return -1;
|
||||
|
||||
/* Set maximum number of open file descriptors */
|
||||
if (getrlimit(RLIMIT_NOFILE, &rlim) < 0)
|
||||
return -1;
|
||||
|
||||
fdlim = (*_st_eventsys->fd_getlimit)();
|
||||
if (fdlim > 0 && rlim.rlim_max > (rlim_t) fdlim) {
|
||||
rlim.rlim_max = fdlim;
|
||||
}
|
||||
rlim.rlim_cur = rlim.rlim_max;
|
||||
if (setrlimit(RLIMIT_NOFILE, &rlim) < 0)
|
||||
return -1;
|
||||
_st_osfd_limit = (int) rlim.rlim_max;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int st_getfdlimit(void)
|
||||
{
|
||||
return _st_osfd_limit;
|
||||
}
|
||||
|
||||
|
||||
void st_netfd_free(_st_netfd_t *fd)
|
||||
{
|
||||
if (!fd->inuse)
|
||||
return;
|
||||
|
||||
fd->inuse = 0;
|
||||
if (fd->aux_data)
|
||||
_st_netfd_free_aux_data(fd);
|
||||
if (fd->private_data && fd->destructor)
|
||||
(*(fd->destructor))(fd->private_data);
|
||||
fd->private_data = NULL;
|
||||
fd->destructor = NULL;
|
||||
fd->next = _st_netfd_freelist;
|
||||
_st_netfd_freelist = fd;
|
||||
}
|
||||
|
||||
|
||||
static _st_netfd_t *_st_netfd_new(int osfd, int nonblock, int is_socket)
|
||||
{
|
||||
_st_netfd_t *fd;
|
||||
int flags = 1;
|
||||
|
||||
if ((*_st_eventsys->fd_new)(osfd) < 0)
|
||||
return NULL;
|
||||
|
||||
if (_st_netfd_freelist) {
|
||||
fd = _st_netfd_freelist;
|
||||
_st_netfd_freelist = _st_netfd_freelist->next;
|
||||
} else {
|
||||
fd = calloc(1, sizeof(_st_netfd_t));
|
||||
if (!fd)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fd->osfd = osfd;
|
||||
fd->inuse = 1;
|
||||
fd->next = NULL;
|
||||
|
||||
if (nonblock) {
|
||||
/* Use just one system call */
|
||||
if (is_socket && ioctl(osfd, FIONBIO, &flags) != -1)
|
||||
return fd;
|
||||
/* Do it the Posix way */
|
||||
if ((flags = fcntl(osfd, F_GETFL, 0)) < 0 ||
|
||||
fcntl(osfd, F_SETFL, flags | O_NONBLOCK) < 0) {
|
||||
st_netfd_free(fd);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
|
||||
_st_netfd_t *st_netfd_open(int osfd)
|
||||
{
|
||||
return _st_netfd_new(osfd, 1, 0);
|
||||
}
|
||||
|
||||
|
||||
_st_netfd_t *st_netfd_open_socket(int osfd)
|
||||
{
|
||||
return _st_netfd_new(osfd, 1, 1);
|
||||
}
|
||||
|
||||
|
||||
int st_netfd_close(_st_netfd_t *fd)
|
||||
{
|
||||
if ((*_st_eventsys->fd_close)(fd->osfd) < 0)
|
||||
return -1;
|
||||
|
||||
st_netfd_free(fd);
|
||||
return close(fd->osfd);
|
||||
}
|
||||
|
||||
|
||||
int st_netfd_fileno(_st_netfd_t *fd)
|
||||
{
|
||||
return (fd->osfd);
|
||||
}
|
||||
|
||||
|
||||
void st_netfd_setspecific(_st_netfd_t *fd, void *value,
|
||||
_st_destructor_t destructor)
|
||||
{
|
||||
if (value != fd->private_data) {
|
||||
/* Free up previously set non-NULL data value */
|
||||
if (fd->private_data && fd->destructor)
|
||||
(*(fd->destructor))(fd->private_data);
|
||||
}
|
||||
fd->private_data = value;
|
||||
fd->destructor = destructor;
|
||||
}
|
||||
|
||||
|
||||
void *st_netfd_getspecific(_st_netfd_t *fd)
|
||||
{
|
||||
return (fd->private_data);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Wait for I/O on a single descriptor.
|
||||
*/
|
||||
int st_netfd_poll(_st_netfd_t *fd, int how, st_utime_t timeout)
|
||||
{
|
||||
struct pollfd pd;
|
||||
int n;
|
||||
|
||||
pd.fd = fd->osfd;
|
||||
pd.events = (short) how;
|
||||
pd.revents = 0;
|
||||
|
||||
if ((n = st_poll(&pd, 1, timeout)) < 0)
|
||||
return -1;
|
||||
if (n == 0) {
|
||||
/* Timed out */
|
||||
errno = ETIME;
|
||||
return -1;
|
||||
}
|
||||
if (pd.revents & POLLNVAL) {
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#ifdef MD_ALWAYS_UNSERIALIZED_ACCEPT
|
||||
/* No-op */
|
||||
int st_netfd_serialize_accept(_st_netfd_t *fd)
|
||||
{
|
||||
fd->aux_data = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* No-op */
|
||||
static void _st_netfd_free_aux_data(_st_netfd_t *fd)
|
||||
{
|
||||
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;
|
||||
|
||||
while ((osfd = accept(fd->osfd, addr, (socklen_t *)addrlen)) < 0) {
|
||||
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;
|
||||
}
|
||||
|
||||
#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)
|
||||
{
|
||||
int n, err = 0;
|
||||
|
||||
while (connect(fd->osfd, addr, addrlen) < 0) {
|
||||
if (errno != EINTR) {
|
||||
/*
|
||||
* On some platforms, if connect() is interrupted (errno == EINTR)
|
||||
* after the kernel binds the socket, a subsequent connect()
|
||||
* attempt will fail with errno == EADDRINUSE. Ignore EADDRINUSE
|
||||
* iff connect() was previously interrupted. See Rich Stevens'
|
||||
* "UNIX Network Programming," Vol. 1, 2nd edition, p. 413
|
||||
* ("Interrupted connect").
|
||||
*/
|
||||
if (errno != EINPROGRESS && (errno != EADDRINUSE || err == 0))
|
||||
return -1;
|
||||
/* Wait until the socket becomes writable */
|
||||
if (st_netfd_poll(fd, POLLOUT, timeout) < 0)
|
||||
return -1;
|
||||
/* Try to find out whether the connection setup succeeded or failed */
|
||||
n = sizeof(int);
|
||||
if (getsockopt(fd->osfd, SOL_SOCKET, SO_ERROR, (char *)&err,
|
||||
(socklen_t *)&n) < 0)
|
||||
return -1;
|
||||
if (err) {
|
||||
errno = err;
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
err = 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
ssize_t st_read(_st_netfd_t *fd, void *buf, size_t nbyte, st_utime_t timeout)
|
||||
{
|
||||
ssize_t n;
|
||||
|
||||
while ((n = read(fd->osfd, buf, nbyte)) < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
if (!_IO_NOT_READY_ERROR)
|
||||
return -1;
|
||||
/* Wait until the socket becomes readable */
|
||||
if (st_netfd_poll(fd, POLLIN, timeout) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
int st_read_resid(_st_netfd_t *fd, void *buf, size_t *resid,
|
||||
st_utime_t timeout)
|
||||
{
|
||||
struct iovec iov, *riov;
|
||||
int riov_size, rv;
|
||||
|
||||
iov.iov_base = buf;
|
||||
iov.iov_len = *resid;
|
||||
riov = &iov;
|
||||
riov_size = 1;
|
||||
rv = st_readv_resid(fd, &riov, &riov_size, timeout);
|
||||
*resid = iov.iov_len;
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
ssize_t st_readv(_st_netfd_t *fd, const struct iovec *iov, int iov_size,
|
||||
st_utime_t timeout)
|
||||
{
|
||||
ssize_t n;
|
||||
|
||||
while ((n = readv(fd->osfd, iov, iov_size)) < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
if (!_IO_NOT_READY_ERROR)
|
||||
return -1;
|
||||
/* Wait until the socket becomes readable */
|
||||
if (st_netfd_poll(fd, POLLIN, timeout) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
int st_readv_resid(_st_netfd_t *fd, struct iovec **iov, int *iov_size,
|
||||
st_utime_t timeout)
|
||||
{
|
||||
ssize_t n;
|
||||
|
||||
while (*iov_size > 0) {
|
||||
if (*iov_size == 1)
|
||||
n = read(fd->osfd, (*iov)->iov_base, (*iov)->iov_len);
|
||||
else
|
||||
n = readv(fd->osfd, *iov, *iov_size);
|
||||
if (n < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
if (!_IO_NOT_READY_ERROR)
|
||||
return -1;
|
||||
} else if (n == 0)
|
||||
break;
|
||||
else {
|
||||
while ((size_t) n >= (*iov)->iov_len) {
|
||||
n -= (*iov)->iov_len;
|
||||
(*iov)->iov_base = (char *) (*iov)->iov_base + (*iov)->iov_len;
|
||||
(*iov)->iov_len = 0;
|
||||
(*iov)++;
|
||||
(*iov_size)--;
|
||||
if (n == 0)
|
||||
break;
|
||||
}
|
||||
if (*iov_size == 0)
|
||||
break;
|
||||
(*iov)->iov_base = (char *) (*iov)->iov_base + n;
|
||||
(*iov)->iov_len -= n;
|
||||
}
|
||||
/* Wait until the socket becomes readable */
|
||||
if (st_netfd_poll(fd, POLLIN, timeout) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
ssize_t st_read_fully(_st_netfd_t *fd, void *buf, size_t nbyte,
|
||||
st_utime_t timeout)
|
||||
{
|
||||
size_t resid = nbyte;
|
||||
return st_read_resid(fd, buf, &resid, timeout) == 0 ?
|
||||
(ssize_t) (nbyte - resid) : -1;
|
||||
}
|
||||
|
||||
|
||||
int st_write_resid(_st_netfd_t *fd, const void *buf, size_t *resid,
|
||||
st_utime_t timeout)
|
||||
{
|
||||
struct iovec iov, *riov;
|
||||
int riov_size, rv;
|
||||
|
||||
iov.iov_base = (void *) buf; /* we promise not to modify buf */
|
||||
iov.iov_len = *resid;
|
||||
riov = &iov;
|
||||
riov_size = 1;
|
||||
rv = st_writev_resid(fd, &riov, &riov_size, timeout);
|
||||
*resid = iov.iov_len;
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
ssize_t st_write(_st_netfd_t *fd, const void *buf, size_t nbyte,
|
||||
st_utime_t timeout)
|
||||
{
|
||||
size_t resid = nbyte;
|
||||
return st_write_resid(fd, buf, &resid, timeout) == 0 ?
|
||||
(ssize_t) (nbyte - resid) : -1;
|
||||
}
|
||||
|
||||
|
||||
ssize_t st_writev(_st_netfd_t *fd, const struct iovec *iov, int iov_size,
|
||||
st_utime_t timeout)
|
||||
{
|
||||
ssize_t n, rv;
|
||||
size_t nleft, nbyte;
|
||||
int index, iov_cnt;
|
||||
struct iovec *tmp_iov;
|
||||
struct iovec local_iov[_LOCAL_MAXIOV];
|
||||
|
||||
/* Calculate the total number of bytes to be sent */
|
||||
nbyte = 0;
|
||||
for (index = 0; index < iov_size; index++)
|
||||
nbyte += iov[index].iov_len;
|
||||
|
||||
rv = (ssize_t)nbyte;
|
||||
nleft = nbyte;
|
||||
tmp_iov = (struct iovec *) iov; /* we promise not to modify iov */
|
||||
iov_cnt = iov_size;
|
||||
|
||||
while (nleft > 0) {
|
||||
if (iov_cnt == 1) {
|
||||
if (st_write(fd, tmp_iov[0].iov_base, nleft, timeout) != (ssize_t) nleft)
|
||||
rv = -1;
|
||||
break;
|
||||
}
|
||||
if ((n = writev(fd->osfd, tmp_iov, iov_cnt)) < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
if (!_IO_NOT_READY_ERROR) {
|
||||
rv = -1;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if ((size_t) n == nleft)
|
||||
break;
|
||||
nleft -= n;
|
||||
/* Find the next unwritten vector */
|
||||
n = (ssize_t)(nbyte - nleft);
|
||||
for (index = 0; (size_t) n >= iov[index].iov_len; index++)
|
||||
n -= iov[index].iov_len;
|
||||
|
||||
if (tmp_iov == iov) {
|
||||
/* Must copy iov's around */
|
||||
if (iov_size - index <= _LOCAL_MAXIOV) {
|
||||
tmp_iov = local_iov;
|
||||
} else {
|
||||
tmp_iov = calloc(1, (iov_size - index) * sizeof(struct iovec));
|
||||
if (tmp_iov == NULL)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Fill in the first partial read */
|
||||
tmp_iov[0].iov_base = &(((char *)iov[index].iov_base)[n]);
|
||||
tmp_iov[0].iov_len = iov[index].iov_len - n;
|
||||
index++;
|
||||
/* Copy the remaining vectors */
|
||||
for (iov_cnt = 1; index < iov_size; iov_cnt++, index++) {
|
||||
tmp_iov[iov_cnt].iov_base = iov[index].iov_base;
|
||||
tmp_iov[iov_cnt].iov_len = iov[index].iov_len;
|
||||
}
|
||||
}
|
||||
/* Wait until the socket becomes writable */
|
||||
if (st_netfd_poll(fd, POLLOUT, timeout) < 0) {
|
||||
rv = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (tmp_iov != iov && tmp_iov != local_iov)
|
||||
free(tmp_iov);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
int st_writev_resid(_st_netfd_t *fd, struct iovec **iov, int *iov_size,
|
||||
st_utime_t timeout)
|
||||
{
|
||||
ssize_t n;
|
||||
|
||||
while (*iov_size > 0) {
|
||||
if (*iov_size == 1)
|
||||
n = write(fd->osfd, (*iov)->iov_base, (*iov)->iov_len);
|
||||
else
|
||||
n = writev(fd->osfd, *iov, *iov_size);
|
||||
if (n < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
if (!_IO_NOT_READY_ERROR)
|
||||
return -1;
|
||||
} else {
|
||||
while ((size_t) n >= (*iov)->iov_len) {
|
||||
n -= (*iov)->iov_len;
|
||||
(*iov)->iov_base = (char *) (*iov)->iov_base + (*iov)->iov_len;
|
||||
(*iov)->iov_len = 0;
|
||||
(*iov)++;
|
||||
(*iov_size)--;
|
||||
if (n == 0)
|
||||
break;
|
||||
}
|
||||
if (*iov_size == 0)
|
||||
break;
|
||||
(*iov)->iov_base = (char *) (*iov)->iov_base + n;
|
||||
(*iov)->iov_len -= n;
|
||||
}
|
||||
/* Wait until the socket becomes writable */
|
||||
if (st_netfd_poll(fd, POLLOUT, timeout) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Simple I/O functions for UDP.
|
||||
*/
|
||||
int st_recvfrom(_st_netfd_t *fd, void *buf, int len, struct sockaddr *from,
|
||||
int *fromlen, st_utime_t timeout)
|
||||
{
|
||||
int n;
|
||||
|
||||
while ((n = recvfrom(fd->osfd, buf, len, 0, from, (socklen_t *)fromlen))
|
||||
< 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
if (!_IO_NOT_READY_ERROR)
|
||||
return -1;
|
||||
/* Wait until the socket becomes readable */
|
||||
if (st_netfd_poll(fd, POLLIN, timeout) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
int st_sendto(_st_netfd_t *fd, const void *msg, int len,
|
||||
const struct sockaddr *to, int tolen, st_utime_t timeout)
|
||||
{
|
||||
int n;
|
||||
|
||||
while ((n = sendto(fd->osfd, msg, len, 0, to, tolen)) < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
if (!_IO_NOT_READY_ERROR)
|
||||
return -1;
|
||||
/* Wait until the socket becomes writable */
|
||||
if (st_netfd_poll(fd, POLLOUT, timeout) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
int st_recvmsg(_st_netfd_t *fd, struct msghdr *msg, int flags,
|
||||
st_utime_t timeout)
|
||||
{
|
||||
int n;
|
||||
|
||||
while ((n = recvmsg(fd->osfd, msg, flags)) < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
if (!_IO_NOT_READY_ERROR)
|
||||
return -1;
|
||||
/* Wait until the socket becomes readable */
|
||||
if (st_netfd_poll(fd, POLLIN, timeout) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
int st_sendmsg(_st_netfd_t *fd, const struct msghdr *msg, int flags,
|
||||
st_utime_t timeout)
|
||||
{
|
||||
int n;
|
||||
|
||||
while ((n = sendmsg(fd->osfd, msg, flags)) < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
if (!_IO_NOT_READY_ERROR)
|
||||
return -1;
|
||||
/* Wait until the socket becomes writable */
|
||||
if (st_netfd_poll(fd, POLLOUT, timeout) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* To open FIFOs or other special files.
|
||||
*/
|
||||
_st_netfd_t *st_open(const char *path, int oflags, mode_t mode)
|
||||
{
|
||||
int osfd, err;
|
||||
_st_netfd_t *newfd;
|
||||
|
||||
while ((osfd = open(path, oflags | O_NONBLOCK, mode)) < 0) {
|
||||
if (errno != EINTR)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
newfd = _st_netfd_new(osfd, 0, 0);
|
||||
if (!newfd) {
|
||||
err = errno;
|
||||
close(osfd);
|
||||
errno = err;
|
||||
}
|
||||
|
||||
return newfd;
|
||||
}
|
||||
|
121
trunk/research/st/key.c
Normal file
121
trunk/research/st/key.c
Normal file
|
@ -0,0 +1,121 @@
|
|||
/*
|
||||
* 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 Netscape Portable Runtime library.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1994-2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Silicon Graphics, Inc.
|
||||
*
|
||||
* Portions created by SGI are Copyright (C) 2000-2001 Silicon
|
||||
* Graphics, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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 is derived directly from Netscape Communications Corporation,
|
||||
* and consists of extensive modifications made during the year(s) 1999-2000.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include "common.h"
|
||||
|
||||
|
||||
/*
|
||||
* Destructor table for per-thread private data
|
||||
*/
|
||||
static _st_destructor_t _st_destructors[ST_KEYS_MAX];
|
||||
static int key_max = 0;
|
||||
|
||||
|
||||
/*
|
||||
* Return a key to be used for thread specific data
|
||||
*/
|
||||
int st_key_create(int *keyp, _st_destructor_t destructor)
|
||||
{
|
||||
if (key_max >= ST_KEYS_MAX) {
|
||||
errno = EAGAIN;
|
||||
return -1;
|
||||
}
|
||||
|
||||
*keyp = key_max++;
|
||||
_st_destructors[*keyp] = destructor;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int st_key_getlimit(void)
|
||||
{
|
||||
return ST_KEYS_MAX;
|
||||
}
|
||||
|
||||
|
||||
int st_thread_setspecific(int key, void *value)
|
||||
{
|
||||
_st_thread_t *me = _ST_CURRENT_THREAD();
|
||||
|
||||
if (key < 0 || key >= key_max) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (value != me->private_data[key]) {
|
||||
/* free up previously set non-NULL data value */
|
||||
if (me->private_data[key] && _st_destructors[key]) {
|
||||
(*_st_destructors[key])(me->private_data[key]);
|
||||
}
|
||||
me->private_data[key] = value;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void *st_thread_getspecific(int key)
|
||||
{
|
||||
if (key < 0 || key >= key_max)
|
||||
return NULL;
|
||||
|
||||
return ((_ST_CURRENT_THREAD())->private_data[key]);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Free up all per-thread private data
|
||||
*/
|
||||
void _st_thread_cleanup(_st_thread_t *thread)
|
||||
{
|
||||
int key;
|
||||
|
||||
for (key = 0; key < key_max; key++) {
|
||||
if (thread->private_data[key] && _st_destructors[key]) {
|
||||
(*_st_destructors[key])(thread->private_data[key]);
|
||||
thread->private_data[key] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
431
trunk/research/st/md.S
Normal file
431
trunk/research/st/md.S
Normal file
|
@ -0,0 +1,431 @@
|
|||
/*
|
||||
* Portions created by SGI are Copyright (C) 2000 Silicon Graphics, Inc.
|
||||
* 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__)
|
||||
|
||||
/*
|
||||
* Internal __jmp_buf layout
|
||||
*/
|
||||
#define JB_BX 0
|
||||
#define JB_SI 1
|
||||
#define JB_DI 2
|
||||
#define JB_BP 3
|
||||
#define JB_SP 4
|
||||
#define JB_PC 5
|
||||
|
||||
.file "md.S"
|
||||
.text
|
||||
|
||||
/* _st_md_cxt_save(__jmp_buf env) */
|
||||
.globl _st_md_cxt_save
|
||||
.type _st_md_cxt_save, @function
|
||||
.align 16
|
||||
_st_md_cxt_save:
|
||||
movl 4(%esp), %eax
|
||||
|
||||
/*
|
||||
* Save registers.
|
||||
*/
|
||||
movl %ebx, (JB_BX*4)(%eax)
|
||||
movl %esi, (JB_SI*4)(%eax)
|
||||
movl %edi, (JB_DI*4)(%eax)
|
||||
/* Save SP */
|
||||
leal 4(%esp), %ecx
|
||||
movl %ecx, (JB_SP*4)(%eax)
|
||||
/* Save PC we are returning to */
|
||||
movl 0(%esp), %ecx
|
||||
movl %ecx, (JB_PC*4)(%eax)
|
||||
/* Save caller frame pointer */
|
||||
movl %ebp, (JB_BP*4)(%eax)
|
||||
xorl %eax, %eax
|
||||
ret
|
||||
.size _st_md_cxt_save, .-_st_md_cxt_save
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
|
||||
/* _st_md_cxt_restore(__jmp_buf env, int val) */
|
||||
.globl _st_md_cxt_restore
|
||||
.type _st_md_cxt_restore, @function
|
||||
.align 16
|
||||
_st_md_cxt_restore:
|
||||
/* First argument is jmp_buf */
|
||||
movl 4(%esp), %ecx
|
||||
/* Second argument is return value */
|
||||
movl 8(%esp), %eax
|
||||
/* Set the return address */
|
||||
movl (JB_PC*4)(%ecx), %edx
|
||||
/*
|
||||
* Restore registers.
|
||||
*/
|
||||
movl (JB_BX*4)(%ecx), %ebx
|
||||
movl (JB_SI*4)(%ecx), %esi
|
||||
movl (JB_DI*4)(%ecx), %edi
|
||||
movl (JB_BP*4)(%ecx), %ebp
|
||||
movl (JB_SP*4)(%ecx), %esp
|
||||
testl %eax, %eax
|
||||
jnz 1f
|
||||
incl %eax
|
||||
/* Jump to saved PC */
|
||||
1: jmp *%edx
|
||||
.size _st_md_cxt_restore, .-_st_md_cxt_restore
|
||||
|
||||
/****************************************************************/
|
||||
|
||||
#elif defined(__amd64__) || defined(__x86_64__)
|
||||
|
||||
/*
|
||||
* Internal __jmp_buf layout
|
||||
*/
|
||||
#define JB_RBX 0
|
||||
#define JB_RBP 1
|
||||
#define JB_R12 2
|
||||
#define JB_R13 3
|
||||
#define JB_R14 4
|
||||
#define JB_R15 5
|
||||
#define JB_RSP 6
|
||||
#define JB_PC 7
|
||||
|
||||
.file "md.S"
|
||||
.text
|
||||
|
||||
/* _st_md_cxt_save(__jmp_buf env) */
|
||||
.globl _st_md_cxt_save
|
||||
.type _st_md_cxt_save, @function
|
||||
.align 16
|
||||
_st_md_cxt_save:
|
||||
/*
|
||||
* Save registers.
|
||||
*/
|
||||
movq %rbx, (JB_RBX*8)(%rdi)
|
||||
movq %rbp, (JB_RBP*8)(%rdi)
|
||||
movq %r12, (JB_R12*8)(%rdi)
|
||||
movq %r13, (JB_R13*8)(%rdi)
|
||||
movq %r14, (JB_R14*8)(%rdi)
|
||||
movq %r15, (JB_R15*8)(%rdi)
|
||||
/* Save SP */
|
||||
leaq 8(%rsp), %rdx
|
||||
movq %rdx, (JB_RSP*8)(%rdi)
|
||||
/* Save PC we are returning to */
|
||||
movq (%rsp), %rax
|
||||
movq %rax, (JB_PC*8)(%rdi)
|
||||
xorq %rax, %rax
|
||||
ret
|
||||
.size _st_md_cxt_save, .-_st_md_cxt_save
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
|
||||
/* _st_md_cxt_restore(__jmp_buf env, int val) */
|
||||
.globl _st_md_cxt_restore
|
||||
.type _st_md_cxt_restore, @function
|
||||
.align 16
|
||||
_st_md_cxt_restore:
|
||||
/*
|
||||
* Restore registers.
|
||||
*/
|
||||
movq (JB_RBX*8)(%rdi), %rbx
|
||||
movq (JB_RBP*8)(%rdi), %rbp
|
||||
movq (JB_R12*8)(%rdi), %r12
|
||||
movq (JB_R13*8)(%rdi), %r13
|
||||
movq (JB_R14*8)(%rdi), %r14
|
||||
movq (JB_R15*8)(%rdi), %r15
|
||||
/* Set return value */
|
||||
test %esi, %esi
|
||||
mov $01, %eax
|
||||
cmove %eax, %esi
|
||||
mov %esi, %eax
|
||||
movq (JB_PC*8)(%rdi), %rdx
|
||||
movq (JB_RSP*8)(%rdi), %rsp
|
||||
/* Jump to saved PC */
|
||||
jmpq *%rdx
|
||||
.size _st_md_cxt_restore, .-_st_md_cxt_restore
|
||||
|
||||
/****************************************************************/
|
||||
|
||||
#endif
|
||||
|
627
trunk/research/st/md.h
Normal file
627
trunk/research/st/md.h
Normal file
|
@ -0,0 +1,627 @@
|
|||
/*
|
||||
* 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 Netscape Portable Runtime library.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1994-2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Silicon Graphics, Inc.
|
||||
*
|
||||
* Portions created by SGI are Copyright (C) 2000-2001 Silicon
|
||||
* Graphics, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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 is derived directly from Netscape Communications Corporation,
|
||||
* and consists of extensive modifications made during the year(s) 1999-2000.
|
||||
*/
|
||||
|
||||
#ifndef __ST_MD_H__
|
||||
#define __ST_MD_H__
|
||||
|
||||
#if defined(ETIMEDOUT) && !defined(ETIME)
|
||||
#define ETIME ETIMEDOUT
|
||||
#endif
|
||||
|
||||
#if defined(MAP_ANONYMOUS) && !defined(MAP_ANON)
|
||||
#define MAP_ANON MAP_ANONYMOUS
|
||||
#endif
|
||||
|
||||
#ifndef MAP_FAILED
|
||||
#define MAP_FAILED -1
|
||||
#endif
|
||||
|
||||
/*****************************************
|
||||
* Platform specifics
|
||||
*/
|
||||
|
||||
#if defined (AIX)
|
||||
|
||||
#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_SETJMP(env) _setjmp(env)
|
||||
#define MD_LONGJMP(env, val) _longjmp(env, val)
|
||||
|
||||
#if defined(__ppc__)
|
||||
#define MD_JB_SP 0
|
||||
#elif defined(__i386__)
|
||||
#define MD_JB_SP 9
|
||||
#elif defined(__x86_64__)
|
||||
#define MD_JB_SP 4
|
||||
#else
|
||||
#error Unknown CPU architecture
|
||||
#endif
|
||||
|
||||
#define MD_INIT_CONTEXT(_thread, _sp, _main) \
|
||||
ST_BEGIN_MACRO \
|
||||
if (MD_SETJMP((_thread)->context)) \
|
||||
_main(); \
|
||||
*((long *)&((_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 (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)
|
||||
|
||||
/*
|
||||
* These are properties of the linux kernel and are the same on every
|
||||
* flavor and architecture.
|
||||
*/
|
||||
#define MD_USE_BSD_ANON_MMAP
|
||||
#define MD_ACCEPT_NB_NOT_INHERITED
|
||||
#define MD_ALWAYS_UNSERIALIZED_ACCEPT
|
||||
/*
|
||||
* Modern GNU/Linux is Posix.1g compliant.
|
||||
*/
|
||||
#define MD_HAVE_SOCKLEN_T
|
||||
|
||||
/*
|
||||
* All architectures and flavors of linux have the gettimeofday
|
||||
* function but if you know of a faster way, use it.
|
||||
*/
|
||||
#define MD_GET_UTIME() \
|
||||
struct timeval tv; \
|
||||
(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
|
||||
|
||||
#define MD_INIT_CONTEXT(_thread, _sp, _main) \
|
||||
ST_BEGIN_MACRO \
|
||||
MD_SETJMP((_thread)->context); \
|
||||
_thread->context[0].__jmpbuf[0].__pc = (__ptr_t) _main; \
|
||||
_thread->context[0].__jmpbuf[0].__sp = _sp; \
|
||||
ST_END_MACRO
|
||||
|
||||
#else /* Not IA-64 or mips */
|
||||
|
||||
/*
|
||||
* On linux, there are a few styles of jmpbuf format. These vary based
|
||||
* on architecture/glibc combination.
|
||||
*
|
||||
* Most of the glibc based toggles were lifted from:
|
||||
* mozilla/nsprpub/pr/include/md/_linux.h
|
||||
*/
|
||||
|
||||
/*
|
||||
* Starting with glibc 2.4, JB_SP definitions are not public anymore.
|
||||
* They, however, can still be found in glibc source tree in
|
||||
* architecture-specific "jmpbuf-offsets.h" files.
|
||||
* Most importantly, the content of jmp_buf is mangled by setjmp to make
|
||||
* it completely opaque (the mangling can be disabled by setting the
|
||||
* LD_POINTER_GUARD environment variable before application execution).
|
||||
* Therefore we will use built-in _st_md_cxt_save/_st_md_cxt_restore
|
||||
* functions as a setjmp/longjmp replacement wherever they are available
|
||||
* 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
|
||||
#define MD_USE_BUILTIN_SETJMP
|
||||
|
||||
#if defined(__GLIBC__) && __GLIBC__ >= 2
|
||||
#ifndef JB_SP
|
||||
#define JB_SP 4
|
||||
#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 i386"
|
||||
#define MD_GET_SP(_t) (_t)->context[0].__jmpbuf[0].__sp
|
||||
#endif
|
||||
|
||||
#elif defined(__amd64__) || defined(__x86_64__)
|
||||
#define MD_STACK_GROWS_DOWN
|
||||
#define MD_USE_BUILTIN_SETJMP
|
||||
|
||||
#ifndef JB_RSP
|
||||
#define JB_RSP 6
|
||||
#endif
|
||||
#define MD_GET_SP(_t) (_t)->context[0].__jmpbuf[JB_RSP]
|
||||
|
||||
#elif defined(__arm__)
|
||||
#define MD_STACK_GROWS_DOWN
|
||||
|
||||
#if defined(__GLIBC__) && __GLIBC__ >= 2
|
||||
#define MD_GET_SP(_t) (_t)->context[0].__jmpbuf[20]
|
||||
#else
|
||||
#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 */
|
||||
|
||||
#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
|
||||
|
||||
#endif /* Cases with different MD_INIT_CONTEXT */
|
||||
|
||||
#if defined(MD_USE_BUILTIN_SETJMP) && !defined(USE_LIBC_SETJMP)
|
||||
#define MD_SETJMP(env) _st_md_cxt_save(env)
|
||||
#define MD_LONGJMP(env, val) _st_md_cxt_restore(env, val)
|
||||
|
||||
extern int _st_md_cxt_save(jmp_buf env);
|
||||
extern void _st_md_cxt_restore(jmp_buf env, int val);
|
||||
#else
|
||||
#define MD_SETJMP(env) setjmp(env)
|
||||
#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
|
||||
|
||||
#if !defined(MD_HAVE_SOCKLEN_T) && !defined(socklen_t)
|
||||
#define socklen_t int
|
||||
#endif
|
||||
|
||||
#ifndef MD_CAP_STACK
|
||||
#define MD_CAP_STACK(var_addr)
|
||||
#endif
|
||||
|
||||
#endif /* !__ST_MD_H__ */
|
||||
|
45
trunk/research/st/osguess.sh
Normal file
45
trunk/research/st/osguess.sh
Normal file
|
@ -0,0 +1,45 @@
|
|||
#
|
||||
# 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"
|
||||
|
184
trunk/research/st/public.h
Normal file
184
trunk/research/st/public.h
Normal file
|
@ -0,0 +1,184 @@
|
|||
/*
|
||||
* 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 Netscape Portable Runtime library.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1994-2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Silicon Graphics, Inc.
|
||||
*
|
||||
* Portions created by SGI are Copyright (C) 2000-2001 Silicon
|
||||
* Graphics, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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 __ST_THREAD_H__
|
||||
#define __ST_THREAD_H__
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/uio.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include <poll.h>
|
||||
|
||||
#define ST_VERSION "1.9"
|
||||
#define ST_VERSION_MAJOR 1
|
||||
#define ST_VERSION_MINOR 9
|
||||
|
||||
/* Undefine this to remove the context switch callback feature. */
|
||||
#define ST_SWITCH_CB
|
||||
|
||||
#ifndef ETIME
|
||||
#define ETIME ETIMEDOUT
|
||||
#endif
|
||||
|
||||
#ifndef ST_UTIME_NO_TIMEOUT
|
||||
#define ST_UTIME_NO_TIMEOUT ((st_utime_t) -1LL)
|
||||
#endif
|
||||
|
||||
#ifndef ST_UTIME_NO_WAIT
|
||||
#define ST_UTIME_NO_WAIT 0
|
||||
#endif
|
||||
|
||||
#define ST_EVENTSYS_DEFAULT 0
|
||||
#define ST_EVENTSYS_SELECT 1
|
||||
#define ST_EVENTSYS_POLL 2
|
||||
#define ST_EVENTSYS_ALT 3
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef unsigned long long st_utime_t;
|
||||
typedef struct _st_thread * st_thread_t;
|
||||
typedef struct _st_cond * st_cond_t;
|
||||
typedef struct _st_mutex * st_mutex_t;
|
||||
typedef struct _st_netfd * st_netfd_t;
|
||||
#ifdef ST_SWITCH_CB
|
||||
typedef void (*st_switch_cb_t)(void);
|
||||
#endif
|
||||
|
||||
extern int st_init(void);
|
||||
extern int st_getfdlimit(void);
|
||||
|
||||
extern int st_set_eventsys(int eventsys);
|
||||
extern int st_get_eventsys(void);
|
||||
extern const char *st_get_eventsys_name(void);
|
||||
|
||||
#ifdef ST_SWITCH_CB
|
||||
extern st_switch_cb_t st_set_switch_in_cb(st_switch_cb_t cb);
|
||||
extern st_switch_cb_t st_set_switch_out_cb(st_switch_cb_t cb);
|
||||
#endif
|
||||
|
||||
extern st_thread_t st_thread_self(void);
|
||||
extern void st_thread_exit(void *retval);
|
||||
extern int st_thread_join(st_thread_t thread, void **retvalp);
|
||||
extern void st_thread_interrupt(st_thread_t thread);
|
||||
extern st_thread_t st_thread_create(void *(*start)(void *arg), void *arg,
|
||||
int joinable, int stack_size);
|
||||
extern int st_randomize_stacks(int on);
|
||||
extern int st_set_utime_function(st_utime_t (*func)(void));
|
||||
|
||||
extern st_utime_t st_utime(void);
|
||||
extern st_utime_t st_utime_last_clock(void);
|
||||
extern int st_timecache_set(int on);
|
||||
extern time_t st_time(void);
|
||||
extern int st_usleep(st_utime_t usecs);
|
||||
extern int st_sleep(int secs);
|
||||
extern st_cond_t st_cond_new(void);
|
||||
extern int st_cond_destroy(st_cond_t cvar);
|
||||
extern int st_cond_timedwait(st_cond_t cvar, st_utime_t timeout);
|
||||
extern int st_cond_wait(st_cond_t cvar);
|
||||
extern int st_cond_signal(st_cond_t cvar);
|
||||
extern int st_cond_broadcast(st_cond_t cvar);
|
||||
extern st_mutex_t st_mutex_new(void);
|
||||
extern int st_mutex_destroy(st_mutex_t lock);
|
||||
extern int st_mutex_lock(st_mutex_t lock);
|
||||
extern int st_mutex_unlock(st_mutex_t lock);
|
||||
extern int st_mutex_trylock(st_mutex_t lock);
|
||||
|
||||
extern int st_key_create(int *keyp, void (*destructor)(void *));
|
||||
extern int st_key_getlimit(void);
|
||||
extern int st_thread_setspecific(int key, void *value);
|
||||
extern void *st_thread_getspecific(int key);
|
||||
|
||||
extern st_netfd_t st_netfd_open(int osfd);
|
||||
extern st_netfd_t st_netfd_open_socket(int osfd);
|
||||
extern void st_netfd_free(st_netfd_t fd);
|
||||
extern int st_netfd_close(st_netfd_t fd);
|
||||
extern int st_netfd_fileno(st_netfd_t fd);
|
||||
extern void st_netfd_setspecific(st_netfd_t fd, void *value,
|
||||
void (*destructor)(void *));
|
||||
extern void *st_netfd_getspecific(st_netfd_t fd);
|
||||
extern int st_netfd_serialize_accept(st_netfd_t fd);
|
||||
extern int st_netfd_poll(st_netfd_t fd, int how, st_utime_t timeout);
|
||||
|
||||
extern int st_poll(struct pollfd *pds, int npds, st_utime_t timeout);
|
||||
extern st_netfd_t st_accept(st_netfd_t fd, struct sockaddr *addr, int *addrlen,
|
||||
st_utime_t timeout);
|
||||
extern int st_connect(st_netfd_t fd, const struct sockaddr *addr, int addrlen,
|
||||
st_utime_t timeout);
|
||||
extern ssize_t st_read(st_netfd_t fd, void *buf, size_t nbyte,
|
||||
st_utime_t timeout);
|
||||
extern ssize_t st_read_fully(st_netfd_t fd, void *buf, size_t nbyte,
|
||||
st_utime_t timeout);
|
||||
extern int st_read_resid(st_netfd_t fd, void *buf, size_t *resid,
|
||||
st_utime_t timeout);
|
||||
extern ssize_t st_readv(st_netfd_t fd, const struct iovec *iov, int iov_size,
|
||||
st_utime_t timeout);
|
||||
extern int st_readv_resid(st_netfd_t fd, struct iovec **iov, int *iov_size,
|
||||
st_utime_t timeout);
|
||||
extern ssize_t st_write(st_netfd_t fd, const void *buf, size_t nbyte,
|
||||
st_utime_t timeout);
|
||||
extern int st_write_resid(st_netfd_t fd, const void *buf, size_t *resid,
|
||||
st_utime_t timeout);
|
||||
extern ssize_t st_writev(st_netfd_t fd, const struct iovec *iov, int iov_size,
|
||||
st_utime_t timeout);
|
||||
extern int st_writev_resid(st_netfd_t fd, struct iovec **iov, int *iov_size,
|
||||
st_utime_t timeout);
|
||||
extern int st_recvfrom(st_netfd_t fd, void *buf, int len,
|
||||
struct sockaddr *from, int *fromlen,
|
||||
st_utime_t timeout);
|
||||
extern int st_sendto(st_netfd_t fd, const void *msg, int len,
|
||||
const struct sockaddr *to, int tolen, st_utime_t timeout);
|
||||
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);
|
||||
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_iterate_threads(void);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* !__ST_THREAD_H__ */
|
||||
|
672
trunk/research/st/sched.c
Normal file
672
trunk/research/st/sched.c
Normal file
|
@ -0,0 +1,672 @@
|
|||
/*
|
||||
* 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 Netscape Portable Runtime library.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1994-2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Silicon Graphics, Inc.
|
||||
*
|
||||
* Portions created by SGI are Copyright (C) 2000-2001 Silicon
|
||||
* Graphics, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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 is derived directly from Netscape Communications Corporation,
|
||||
* and consists of extensive modifications made during the year(s) 1999-2000.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include "common.h"
|
||||
|
||||
|
||||
/* Global data */
|
||||
_st_vp_t _st_this_vp; /* This VP */
|
||||
_st_thread_t *_st_this_thread; /* Current thread */
|
||||
int _st_active_count = 0; /* Active thread count */
|
||||
|
||||
time_t _st_curr_time = 0; /* Current time as returned by time(2) */
|
||||
st_utime_t _st_last_tset; /* Last time it was fetched */
|
||||
|
||||
|
||||
int st_poll(struct pollfd *pds, int npds, st_utime_t timeout)
|
||||
{
|
||||
struct pollfd *pd;
|
||||
struct pollfd *epd = pds + npds;
|
||||
_st_pollq_t pq;
|
||||
_st_thread_t *me = _ST_CURRENT_THREAD();
|
||||
int n;
|
||||
|
||||
if (me->flags & _ST_FL_INTERRUPT) {
|
||||
me->flags &= ~_ST_FL_INTERRUPT;
|
||||
errno = EINTR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((*_st_eventsys->pollset_add)(pds, npds) < 0)
|
||||
return -1;
|
||||
|
||||
pq.pds = pds;
|
||||
pq.npds = npds;
|
||||
pq.thread = me;
|
||||
pq.on_ioq = 1;
|
||||
_ST_ADD_IOQ(pq);
|
||||
if (timeout != ST_UTIME_NO_TIMEOUT)
|
||||
_ST_ADD_SLEEPQ(me, timeout);
|
||||
me->state = _ST_ST_IO_WAIT;
|
||||
|
||||
_ST_SWITCH_CONTEXT(me);
|
||||
|
||||
n = 0;
|
||||
if (pq.on_ioq) {
|
||||
/* If we timed out, the pollq might still be on the ioq. Remove it */
|
||||
_ST_DEL_IOQ(pq);
|
||||
(*_st_eventsys->pollset_del)(pds, npds);
|
||||
} else {
|
||||
/* Count the number of ready descriptors */
|
||||
for (pd = pds; pd < epd; pd++) {
|
||||
if (pd->revents)
|
||||
n++;
|
||||
}
|
||||
}
|
||||
|
||||
if (me->flags & _ST_FL_INTERRUPT) {
|
||||
me->flags &= ~_ST_FL_INTERRUPT;
|
||||
errno = EINTR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
void _st_vp_schedule(void)
|
||||
{
|
||||
_st_thread_t *thread;
|
||||
|
||||
if (_ST_RUNQ.next != &_ST_RUNQ) {
|
||||
/* Pull thread off of the run queue */
|
||||
thread = _ST_THREAD_PTR(_ST_RUNQ.next);
|
||||
_ST_DEL_RUNQ(thread);
|
||||
} else {
|
||||
/* If there are no threads to run, switch to the idle thread */
|
||||
thread = _st_this_vp.idle_thread;
|
||||
}
|
||||
ST_ASSERT(thread->state == _ST_ST_RUNNABLE);
|
||||
|
||||
/* Resume the thread */
|
||||
thread->state = _ST_ST_RUNNING;
|
||||
_ST_RESTORE_CONTEXT(thread);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Initialize this Virtual Processor
|
||||
*/
|
||||
int st_init(void)
|
||||
{
|
||||
_st_thread_t *thread;
|
||||
|
||||
if (_st_active_count) {
|
||||
/* Already initialized */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* We can ignore return value here */
|
||||
st_set_eventsys(ST_EVENTSYS_DEFAULT);
|
||||
|
||||
if (_st_io_init() < 0)
|
||||
return -1;
|
||||
|
||||
memset(&_st_this_vp, 0, sizeof(_st_vp_t));
|
||||
|
||||
ST_INIT_CLIST(&_ST_RUNQ);
|
||||
ST_INIT_CLIST(&_ST_IOQ);
|
||||
ST_INIT_CLIST(&_ST_ZOMBIEQ);
|
||||
#ifdef DEBUG
|
||||
ST_INIT_CLIST(&_ST_THREADQ);
|
||||
#endif
|
||||
|
||||
if ((*_st_eventsys->init)() < 0)
|
||||
return -1;
|
||||
|
||||
_st_this_vp.pagesize = getpagesize();
|
||||
_st_this_vp.last_clock = st_utime();
|
||||
|
||||
/*
|
||||
* Create idle thread
|
||||
*/
|
||||
_st_this_vp.idle_thread = st_thread_create(_st_idle_thread_start,
|
||||
NULL, 0, 0);
|
||||
if (!_st_this_vp.idle_thread)
|
||||
return -1;
|
||||
_st_this_vp.idle_thread->flags = _ST_FL_IDLE_THREAD;
|
||||
_st_active_count--;
|
||||
_ST_DEL_RUNQ(_st_this_vp.idle_thread);
|
||||
|
||||
/*
|
||||
* Initialize primordial thread
|
||||
*/
|
||||
thread = (_st_thread_t *) calloc(1, sizeof(_st_thread_t) +
|
||||
(ST_KEYS_MAX * sizeof(void *)));
|
||||
if (!thread)
|
||||
return -1;
|
||||
thread->private_data = (void **) (thread + 1);
|
||||
thread->state = _ST_ST_RUNNING;
|
||||
thread->flags = _ST_FL_PRIMORDIAL;
|
||||
_ST_SET_CURRENT_THREAD(thread);
|
||||
_st_active_count++;
|
||||
#ifdef DEBUG
|
||||
_ST_ADD_THREADQ(thread);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#ifdef ST_SWITCH_CB
|
||||
st_switch_cb_t st_set_switch_in_cb(st_switch_cb_t cb)
|
||||
{
|
||||
st_switch_cb_t ocb = _st_this_vp.switch_in_cb;
|
||||
_st_this_vp.switch_in_cb = cb;
|
||||
return ocb;
|
||||
}
|
||||
|
||||
st_switch_cb_t st_set_switch_out_cb(st_switch_cb_t cb)
|
||||
{
|
||||
st_switch_cb_t ocb = _st_this_vp.switch_out_cb;
|
||||
_st_this_vp.switch_out_cb = cb;
|
||||
return ocb;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Start function for the idle thread
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
void *_st_idle_thread_start(void *arg)
|
||||
{
|
||||
_st_thread_t *me = _ST_CURRENT_THREAD();
|
||||
|
||||
while (_st_active_count > 0) {
|
||||
/* Idle vp till I/O is ready or the smallest timeout expired */
|
||||
_ST_VP_IDLE();
|
||||
|
||||
/* Check sleep queue for expired threads */
|
||||
_st_vp_check_clock();
|
||||
|
||||
me->state = _ST_ST_RUNNABLE;
|
||||
_ST_SWITCH_CONTEXT(me);
|
||||
}
|
||||
|
||||
/* No more threads */
|
||||
exit(0);
|
||||
|
||||
/* NOTREACHED */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void st_thread_exit(void *retval)
|
||||
{
|
||||
_st_thread_t *thread = _ST_CURRENT_THREAD();
|
||||
|
||||
thread->retval = retval;
|
||||
_st_thread_cleanup(thread);
|
||||
_st_active_count--;
|
||||
if (thread->term) {
|
||||
/* Put thread on the zombie queue */
|
||||
thread->state = _ST_ST_ZOMBIE;
|
||||
_ST_ADD_ZOMBIEQ(thread);
|
||||
|
||||
/* Notify on our termination condition variable */
|
||||
st_cond_signal(thread->term);
|
||||
|
||||
/* Switch context and come back later */
|
||||
_ST_SWITCH_CONTEXT(thread);
|
||||
|
||||
/* Continue the cleanup */
|
||||
st_cond_destroy(thread->term);
|
||||
thread->term = NULL;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
_ST_DEL_THREADQ(thread);
|
||||
#endif
|
||||
|
||||
if (!(thread->flags & _ST_FL_PRIMORDIAL))
|
||||
_st_stack_free(thread->stack);
|
||||
|
||||
/* Find another thread to run */
|
||||
_ST_SWITCH_CONTEXT(thread);
|
||||
/* Not going to land here */
|
||||
}
|
||||
|
||||
|
||||
int st_thread_join(_st_thread_t *thread, void **retvalp)
|
||||
{
|
||||
_st_cond_t *term = thread->term;
|
||||
|
||||
/* Can't join a non-joinable thread */
|
||||
if (term == NULL) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (_ST_CURRENT_THREAD() == thread) {
|
||||
errno = EDEADLK;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Multiple threads can't wait on the same joinable thread */
|
||||
if (term->wait_q.next != &term->wait_q) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (thread->state != _ST_ST_ZOMBIE) {
|
||||
if (st_cond_timedwait(term, ST_UTIME_NO_TIMEOUT) != 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (retvalp)
|
||||
*retvalp = thread->retval;
|
||||
|
||||
/*
|
||||
* Remove target thread from the zombie queue and make it runnable.
|
||||
* When it gets scheduled later, it will do the clean up.
|
||||
*/
|
||||
thread->state = _ST_ST_RUNNABLE;
|
||||
_ST_DEL_ZOMBIEQ(thread);
|
||||
_ST_ADD_RUNQ(thread);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void _st_thread_main(void)
|
||||
{
|
||||
_st_thread_t *thread = _ST_CURRENT_THREAD();
|
||||
|
||||
/*
|
||||
* Cap the stack by zeroing out the saved return address register
|
||||
* value. This allows some debugging/profiling tools to know when
|
||||
* to stop unwinding the stack. It's a no-op on most platforms.
|
||||
*/
|
||||
MD_CAP_STACK(&thread);
|
||||
|
||||
/* Run thread main */
|
||||
thread->retval = (*thread->start)(thread->arg);
|
||||
|
||||
/* All done, time to go away */
|
||||
st_thread_exit(thread->retval);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Insert "thread" into the timeout heap, in the position
|
||||
* specified by thread->heap_index. See docs/timeout_heap.txt
|
||||
* for details about the timeout heap.
|
||||
*/
|
||||
static _st_thread_t **heap_insert(_st_thread_t *thread) {
|
||||
int target = thread->heap_index;
|
||||
int s = target;
|
||||
_st_thread_t **p = &_ST_SLEEPQ;
|
||||
int bits = 0;
|
||||
int bit;
|
||||
int index = 1;
|
||||
|
||||
while (s) {
|
||||
s >>= 1;
|
||||
bits++;
|
||||
}
|
||||
for (bit = bits - 2; bit >= 0; bit--) {
|
||||
if (thread->due < (*p)->due) {
|
||||
_st_thread_t *t = *p;
|
||||
thread->left = t->left;
|
||||
thread->right = t->right;
|
||||
*p = thread;
|
||||
thread->heap_index = index;
|
||||
thread = t;
|
||||
}
|
||||
index <<= 1;
|
||||
if (target & (1 << bit)) {
|
||||
p = &((*p)->right);
|
||||
index |= 1;
|
||||
} else {
|
||||
p = &((*p)->left);
|
||||
}
|
||||
}
|
||||
thread->heap_index = index;
|
||||
*p = thread;
|
||||
thread->left = thread->right = NULL;
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Delete "thread" from the timeout heap.
|
||||
*/
|
||||
static void heap_delete(_st_thread_t *thread) {
|
||||
_st_thread_t *t, **p;
|
||||
int bits = 0;
|
||||
int s, bit;
|
||||
|
||||
/* First find and unlink the last heap element */
|
||||
p = &_ST_SLEEPQ;
|
||||
s = _ST_SLEEPQ_SIZE;
|
||||
while (s) {
|
||||
s >>= 1;
|
||||
bits++;
|
||||
}
|
||||
for (bit = bits - 2; bit >= 0; bit--) {
|
||||
if (_ST_SLEEPQ_SIZE & (1 << bit)) {
|
||||
p = &((*p)->right);
|
||||
} else {
|
||||
p = &((*p)->left);
|
||||
}
|
||||
}
|
||||
t = *p;
|
||||
*p = NULL;
|
||||
--_ST_SLEEPQ_SIZE;
|
||||
if (t != thread) {
|
||||
/*
|
||||
* Insert the unlinked last element in place of the element we are deleting
|
||||
*/
|
||||
t->heap_index = thread->heap_index;
|
||||
p = heap_insert(t);
|
||||
t = *p;
|
||||
t->left = thread->left;
|
||||
t->right = thread->right;
|
||||
|
||||
/*
|
||||
* Reestablish the heap invariant.
|
||||
*/
|
||||
for (;;) {
|
||||
_st_thread_t *y; /* The younger child */
|
||||
int index_tmp;
|
||||
if (t->left == NULL)
|
||||
break;
|
||||
else if (t->right == NULL)
|
||||
y = t->left;
|
||||
else if (t->left->due < t->right->due)
|
||||
y = t->left;
|
||||
else
|
||||
y = t->right;
|
||||
if (t->due > y->due) {
|
||||
_st_thread_t *tl = y->left;
|
||||
_st_thread_t *tr = y->right;
|
||||
*p = y;
|
||||
if (y == t->left) {
|
||||
y->left = t;
|
||||
y->right = t->right;
|
||||
p = &y->left;
|
||||
} else {
|
||||
y->left = t->left;
|
||||
y->right = t;
|
||||
p = &y->right;
|
||||
}
|
||||
t->left = tl;
|
||||
t->right = tr;
|
||||
index_tmp = t->heap_index;
|
||||
t->heap_index = y->heap_index;
|
||||
y->heap_index = index_tmp;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
thread->left = thread->right = NULL;
|
||||
}
|
||||
|
||||
|
||||
void _st_add_sleep_q(_st_thread_t *thread, st_utime_t timeout)
|
||||
{
|
||||
thread->due = _ST_LAST_CLOCK + timeout;
|
||||
thread->flags |= _ST_FL_ON_SLEEPQ;
|
||||
thread->heap_index = ++_ST_SLEEPQ_SIZE;
|
||||
heap_insert(thread);
|
||||
}
|
||||
|
||||
|
||||
void _st_del_sleep_q(_st_thread_t *thread)
|
||||
{
|
||||
heap_delete(thread);
|
||||
thread->flags &= ~_ST_FL_ON_SLEEPQ;
|
||||
}
|
||||
|
||||
|
||||
void _st_vp_check_clock(void)
|
||||
{
|
||||
_st_thread_t *thread;
|
||||
st_utime_t elapsed, now;
|
||||
|
||||
now = st_utime();
|
||||
elapsed = now - _ST_LAST_CLOCK;
|
||||
_ST_LAST_CLOCK = now;
|
||||
|
||||
if (_st_curr_time && now - _st_last_tset > 999000) {
|
||||
_st_curr_time = time(NULL);
|
||||
_st_last_tset = now;
|
||||
}
|
||||
|
||||
while (_ST_SLEEPQ != NULL) {
|
||||
thread = _ST_SLEEPQ;
|
||||
ST_ASSERT(thread->flags & _ST_FL_ON_SLEEPQ);
|
||||
if (thread->due > now)
|
||||
break;
|
||||
_ST_DEL_SLEEPQ(thread);
|
||||
|
||||
/* If thread is waiting on condition variable, set the time out flag */
|
||||
if (thread->state == _ST_ST_COND_WAIT)
|
||||
thread->flags |= _ST_FL_TIMEDOUT;
|
||||
|
||||
/* Make thread runnable */
|
||||
ST_ASSERT(!(thread->flags & _ST_FL_IDLE_THREAD));
|
||||
thread->state = _ST_ST_RUNNABLE;
|
||||
_ST_ADD_RUNQ(thread);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void st_thread_interrupt(_st_thread_t *thread)
|
||||
{
|
||||
/* If thread is already dead */
|
||||
if (thread->state == _ST_ST_ZOMBIE)
|
||||
return;
|
||||
|
||||
thread->flags |= _ST_FL_INTERRUPT;
|
||||
|
||||
if (thread->state == _ST_ST_RUNNING || thread->state == _ST_ST_RUNNABLE)
|
||||
return;
|
||||
|
||||
if (thread->flags & _ST_FL_ON_SLEEPQ)
|
||||
_ST_DEL_SLEEPQ(thread);
|
||||
|
||||
/* Make thread runnable */
|
||||
thread->state = _ST_ST_RUNNABLE;
|
||||
_ST_ADD_RUNQ(thread);
|
||||
}
|
||||
|
||||
|
||||
_st_thread_t *st_thread_create(void *(*start)(void *arg), void *arg,
|
||||
int joinable, int stk_size)
|
||||
{
|
||||
_st_thread_t *thread;
|
||||
_st_stack_t *stack;
|
||||
void **ptds;
|
||||
char *sp;
|
||||
#ifdef __ia64__
|
||||
char *bsp;
|
||||
#endif
|
||||
|
||||
/* Adjust stack size */
|
||||
if (stk_size == 0)
|
||||
stk_size = ST_DEFAULT_STACK_SIZE;
|
||||
stk_size = ((stk_size + _ST_PAGE_SIZE - 1) / _ST_PAGE_SIZE) * _ST_PAGE_SIZE;
|
||||
stack = _st_stack_new(stk_size);
|
||||
if (!stack)
|
||||
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);
|
||||
thread = (_st_thread_t *) sp;
|
||||
|
||||
/* Make stack 64-byte aligned */
|
||||
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 *));
|
||||
|
||||
/* Initialize thread */
|
||||
thread->private_data = ptds;
|
||||
thread->stack = stack;
|
||||
thread->start = start;
|
||||
thread->arg = arg;
|
||||
|
||||
#ifndef __ia64__
|
||||
_ST_INIT_CONTEXT(thread, stack->sp, _st_thread_main);
|
||||
#else
|
||||
_ST_INIT_CONTEXT(thread, stack->sp, stack->bsp, _st_thread_main);
|
||||
#endif
|
||||
|
||||
/* If thread is joinable, allocate a termination condition variable */
|
||||
if (joinable) {
|
||||
thread->term = st_cond_new();
|
||||
if (thread->term == NULL) {
|
||||
_st_stack_free(thread->stack);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Make thread runnable */
|
||||
thread->state = _ST_ST_RUNNABLE;
|
||||
_st_active_count++;
|
||||
_ST_ADD_RUNQ(thread);
|
||||
#ifdef DEBUG
|
||||
_ST_ADD_THREADQ(thread);
|
||||
#endif
|
||||
|
||||
return thread;
|
||||
}
|
||||
|
||||
|
||||
_st_thread_t *st_thread_self(void)
|
||||
{
|
||||
return _ST_CURRENT_THREAD();
|
||||
}
|
||||
|
||||
|
||||
#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;
|
||||
|
||||
void _st_iterate_threads(void)
|
||||
{
|
||||
static _st_thread_t *thread = NULL;
|
||||
static jmp_buf orig_jb, save_jb;
|
||||
_st_clist_t *q;
|
||||
|
||||
if (!_st_iterate_threads_flag) {
|
||||
if (thread) {
|
||||
memcpy(thread->context, save_jb, sizeof(jmp_buf));
|
||||
MD_LONGJMP(orig_jb, 1);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (thread) {
|
||||
memcpy(thread->context, save_jb, sizeof(jmp_buf));
|
||||
_st_show_thread_stack(thread, NULL);
|
||||
} else {
|
||||
if (MD_SETJMP(orig_jb)) {
|
||||
_st_iterate_threads_flag = 0;
|
||||
thread = NULL;
|
||||
_st_show_thread_stack(thread, "Iteration completed");
|
||||
return;
|
||||
}
|
||||
thread = _ST_CURRENT_THREAD();
|
||||
_st_show_thread_stack(thread, "Iteration started");
|
||||
}
|
||||
|
||||
q = thread->tlink.next;
|
||||
if (q == &_ST_THREADQ)
|
||||
q = q->next;
|
||||
ST_ASSERT(q != &_ST_THREADQ);
|
||||
thread = _ST_THREAD_THREADQ_PTR(q);
|
||||
if (thread == _ST_CURRENT_THREAD())
|
||||
MD_LONGJMP(orig_jb, 1);
|
||||
memcpy(save_jb, thread->context, sizeof(jmp_buf));
|
||||
MD_LONGJMP(thread->context, 1);
|
||||
}
|
||||
#endif /* DEBUG */
|
||||
|
3
trunk/research/st/st/init
Normal file
3
trunk/research/st/st/init
Normal file
|
@ -0,0 +1,3 @@
|
|||
#ifndef _st_icpp_init_stub
|
||||
#define _st_icpp_init_stub
|
||||
#endif
|
16
trunk/research/st/st/st.upp
Normal file
16
trunk/research/st/st/st.upp
Normal file
|
@ -0,0 +1,16 @@
|
|||
file
|
||||
main readonly separator,
|
||||
..\common.h,
|
||||
..\event.c,
|
||||
..\io.c,
|
||||
..\key.c,
|
||||
..\md.h,
|
||||
..\md.S,
|
||||
..\public.h,
|
||||
..\sched.c,
|
||||
..\stk.c,
|
||||
..\sync.c;
|
||||
|
||||
mainconfig
|
||||
"" = "MAIN";
|
||||
|
173
trunk/research/st/stk.c
Normal file
173
trunk/research/st/stk.c
Normal file
|
@ -0,0 +1,173 @@
|
|||
/*
|
||||
* 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 Netscape Portable Runtime library.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1994-2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Silicon Graphics, Inc.
|
||||
*
|
||||
* Portions created by SGI are Copyright (C) 2000-2001 Silicon
|
||||
* Graphics, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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 is derived directly from Netscape Communications Corporation,
|
||||
* and consists of extensive modifications made during the year(s) 1999-2000.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
#include "common.h"
|
||||
|
||||
|
||||
/* How much space to leave between the stacks, at each end */
|
||||
#define REDZONE _ST_PAGE_SIZE
|
||||
|
||||
_st_clist_t _st_free_stacks = ST_INIT_STATIC_CLIST(&_st_free_stacks);
|
||||
int _st_num_free_stacks = 0;
|
||||
int _st_randomize_stacks = 0;
|
||||
|
||||
static char *_st_new_stk_segment(int size);
|
||||
|
||||
_st_stack_t *_st_stack_new(int stack_size)
|
||||
{
|
||||
_st_clist_t *qp;
|
||||
_st_stack_t *ts;
|
||||
int extra;
|
||||
|
||||
for (qp = _st_free_stacks.next; qp != &_st_free_stacks; qp = qp->next) {
|
||||
ts = _ST_THREAD_STACK_PTR(qp);
|
||||
if (ts->stk_size >= stack_size) {
|
||||
/* Found a stack that is big enough */
|
||||
ST_REMOVE_LINK(&ts->links);
|
||||
_st_num_free_stacks--;
|
||||
ts->links.next = NULL;
|
||||
ts->links.prev = NULL;
|
||||
return ts;
|
||||
}
|
||||
}
|
||||
|
||||
/* Make a new thread stack object. */
|
||||
if ((ts = (_st_stack_t *)calloc(1, sizeof(_st_stack_t))) == NULL)
|
||||
return NULL;
|
||||
extra = _st_randomize_stacks ? _ST_PAGE_SIZE : 0;
|
||||
ts->vaddr_size = stack_size + 2*REDZONE + extra;
|
||||
ts->vaddr = _st_new_stk_segment(ts->vaddr_size);
|
||||
if (!ts->vaddr) {
|
||||
free(ts);
|
||||
return NULL;
|
||||
}
|
||||
ts->stk_size = stack_size;
|
||||
ts->stk_bottom = ts->vaddr + REDZONE;
|
||||
ts->stk_top = ts->stk_bottom + stack_size;
|
||||
|
||||
#ifdef DEBUG
|
||||
mprotect(ts->vaddr, REDZONE, PROT_NONE);
|
||||
mprotect(ts->stk_top + extra, REDZONE, PROT_NONE);
|
||||
#endif
|
||||
|
||||
if (extra) {
|
||||
long offset = (random() % extra) & ~0xf;
|
||||
|
||||
ts->stk_bottom += offset;
|
||||
ts->stk_top += offset;
|
||||
}
|
||||
|
||||
return ts;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Free the stack for the current thread
|
||||
*/
|
||||
void _st_stack_free(_st_stack_t *ts)
|
||||
{
|
||||
if (!ts)
|
||||
return;
|
||||
|
||||
/* Put the stack on the free list */
|
||||
ST_APPEND_LINK(&ts->links, _st_free_stacks.prev);
|
||||
_st_num_free_stacks++;
|
||||
}
|
||||
|
||||
|
||||
static char *_st_new_stk_segment(int size)
|
||||
{
|
||||
#ifdef MALLOC_STACK
|
||||
void *vaddr = malloc(size);
|
||||
#else
|
||||
static int zero_fd = -1;
|
||||
int mmap_flags = MAP_PRIVATE;
|
||||
void *vaddr;
|
||||
|
||||
#if defined (MD_USE_SYSV_ANON_MMAP)
|
||||
if (zero_fd < 0) {
|
||||
if ((zero_fd = open("/dev/zero", O_RDWR, 0)) < 0)
|
||||
return NULL;
|
||||
fcntl(zero_fd, F_SETFD, FD_CLOEXEC);
|
||||
}
|
||||
#elif defined (MD_USE_BSD_ANON_MMAP)
|
||||
mmap_flags |= MAP_ANON;
|
||||
#else
|
||||
#error Unknown OS
|
||||
#endif
|
||||
|
||||
vaddr = mmap(NULL, size, PROT_READ | PROT_WRITE, mmap_flags, zero_fd, 0);
|
||||
if (vaddr == (void *)MAP_FAILED)
|
||||
return NULL;
|
||||
|
||||
#endif /* MALLOC_STACK */
|
||||
|
||||
return (char *)vaddr;
|
||||
}
|
||||
|
||||
|
||||
/* Not used */
|
||||
#if 0
|
||||
void _st_delete_stk_segment(char *vaddr, int size)
|
||||
{
|
||||
#ifdef MALLOC_STACK
|
||||
free(vaddr);
|
||||
#else
|
||||
(void) munmap(vaddr, size);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
int st_randomize_stacks(int on)
|
||||
{
|
||||
int wason = _st_randomize_stacks;
|
||||
|
||||
_st_randomize_stacks = on;
|
||||
if (on)
|
||||
srandom((unsigned int) st_utime());
|
||||
|
||||
return wason;
|
||||
}
|
369
trunk/research/st/sync.c
Normal file
369
trunk/research/st/sync.c
Normal file
|
@ -0,0 +1,369 @@
|
|||
/*
|
||||
* 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 Netscape Portable Runtime library.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1994-2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Silicon Graphics, Inc.
|
||||
*
|
||||
* Portions created by SGI are Copyright (C) 2000-2001 Silicon
|
||||
* Graphics, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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 is derived directly from Netscape Communications Corporation,
|
||||
* and consists of extensive modifications made during the year(s) 1999-2000.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include "common.h"
|
||||
|
||||
|
||||
extern time_t _st_curr_time;
|
||||
extern st_utime_t _st_last_tset;
|
||||
extern int _st_active_count;
|
||||
|
||||
static st_utime_t (*_st_utime)(void) = NULL;
|
||||
|
||||
|
||||
/*****************************************
|
||||
* Time functions
|
||||
*/
|
||||
|
||||
st_utime_t st_utime(void)
|
||||
{
|
||||
if (_st_utime == NULL) {
|
||||
#ifdef MD_GET_UTIME
|
||||
MD_GET_UTIME();
|
||||
#else
|
||||
#error Unknown OS
|
||||
#endif
|
||||
}
|
||||
|
||||
return (*_st_utime)();
|
||||
}
|
||||
|
||||
|
||||
int st_set_utime_function(st_utime_t (*func)(void))
|
||||
{
|
||||
if (_st_active_count) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
_st_utime = func;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
st_utime_t st_utime_last_clock(void)
|
||||
{
|
||||
return _ST_LAST_CLOCK;
|
||||
}
|
||||
|
||||
|
||||
int st_timecache_set(int on)
|
||||
{
|
||||
int wason = (_st_curr_time) ? 1 : 0;
|
||||
|
||||
if (on) {
|
||||
_st_curr_time = time(NULL);
|
||||
_st_last_tset = st_utime();
|
||||
} else
|
||||
_st_curr_time = 0;
|
||||
|
||||
return wason;
|
||||
}
|
||||
|
||||
|
||||
time_t st_time(void)
|
||||
{
|
||||
if (_st_curr_time)
|
||||
return _st_curr_time;
|
||||
|
||||
return time(NULL);
|
||||
}
|
||||
|
||||
|
||||
int st_usleep(st_utime_t usecs)
|
||||
{
|
||||
_st_thread_t *me = _ST_CURRENT_THREAD();
|
||||
|
||||
if (me->flags & _ST_FL_INTERRUPT) {
|
||||
me->flags &= ~_ST_FL_INTERRUPT;
|
||||
errno = EINTR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (usecs != ST_UTIME_NO_TIMEOUT) {
|
||||
me->state = _ST_ST_SLEEPING;
|
||||
_ST_ADD_SLEEPQ(me, usecs);
|
||||
} else
|
||||
me->state = _ST_ST_SUSPENDED;
|
||||
|
||||
_ST_SWITCH_CONTEXT(me);
|
||||
|
||||
if (me->flags & _ST_FL_INTERRUPT) {
|
||||
me->flags &= ~_ST_FL_INTERRUPT;
|
||||
errno = EINTR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int st_sleep(int secs)
|
||||
{
|
||||
return st_usleep((secs >= 0) ? secs * (st_utime_t) 1000000LL :
|
||||
ST_UTIME_NO_TIMEOUT);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************
|
||||
* Condition variable functions
|
||||
*/
|
||||
|
||||
_st_cond_t *st_cond_new(void)
|
||||
{
|
||||
_st_cond_t *cvar;
|
||||
|
||||
cvar = (_st_cond_t *) calloc(1, sizeof(_st_cond_t));
|
||||
if (cvar) {
|
||||
ST_INIT_CLIST(&cvar->wait_q);
|
||||
}
|
||||
|
||||
return cvar;
|
||||
}
|
||||
|
||||
|
||||
int st_cond_destroy(_st_cond_t *cvar)
|
||||
{
|
||||
if (cvar->wait_q.next != &cvar->wait_q) {
|
||||
errno = EBUSY;
|
||||
return -1;
|
||||
}
|
||||
|
||||
free(cvar);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int st_cond_timedwait(_st_cond_t *cvar, st_utime_t timeout)
|
||||
{
|
||||
_st_thread_t *me = _ST_CURRENT_THREAD();
|
||||
int rv;
|
||||
|
||||
if (me->flags & _ST_FL_INTERRUPT) {
|
||||
me->flags &= ~_ST_FL_INTERRUPT;
|
||||
errno = EINTR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Put caller thread on the condition variable's wait queue */
|
||||
me->state = _ST_ST_COND_WAIT;
|
||||
ST_APPEND_LINK(&me->wait_links, &cvar->wait_q);
|
||||
|
||||
if (timeout != ST_UTIME_NO_TIMEOUT)
|
||||
_ST_ADD_SLEEPQ(me, timeout);
|
||||
|
||||
_ST_SWITCH_CONTEXT(me);
|
||||
|
||||
ST_REMOVE_LINK(&me->wait_links);
|
||||
rv = 0;
|
||||
|
||||
if (me->flags & _ST_FL_TIMEDOUT) {
|
||||
me->flags &= ~_ST_FL_TIMEDOUT;
|
||||
errno = ETIME;
|
||||
rv = -1;
|
||||
}
|
||||
if (me->flags & _ST_FL_INTERRUPT) {
|
||||
me->flags &= ~_ST_FL_INTERRUPT;
|
||||
errno = EINTR;
|
||||
rv = -1;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
int st_cond_wait(_st_cond_t *cvar)
|
||||
{
|
||||
return st_cond_timedwait(cvar, ST_UTIME_NO_TIMEOUT);
|
||||
}
|
||||
|
||||
|
||||
static int _st_cond_signal(_st_cond_t *cvar, int broadcast)
|
||||
{
|
||||
_st_thread_t *thread;
|
||||
_st_clist_t *q;
|
||||
|
||||
for (q = cvar->wait_q.next; q != &cvar->wait_q; q = q->next) {
|
||||
thread = _ST_THREAD_WAITQ_PTR(q);
|
||||
if (thread->state == _ST_ST_COND_WAIT) {
|
||||
if (thread->flags & _ST_FL_ON_SLEEPQ)
|
||||
_ST_DEL_SLEEPQ(thread);
|
||||
|
||||
/* Make thread runnable */
|
||||
thread->state = _ST_ST_RUNNABLE;
|
||||
_ST_ADD_RUNQ(thread);
|
||||
if (!broadcast)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int st_cond_signal(_st_cond_t *cvar)
|
||||
{
|
||||
return _st_cond_signal(cvar, 0);
|
||||
}
|
||||
|
||||
|
||||
int st_cond_broadcast(_st_cond_t *cvar)
|
||||
{
|
||||
return _st_cond_signal(cvar, 1);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************
|
||||
* Mutex functions
|
||||
*/
|
||||
|
||||
_st_mutex_t *st_mutex_new(void)
|
||||
{
|
||||
_st_mutex_t *lock;
|
||||
|
||||
lock = (_st_mutex_t *) calloc(1, sizeof(_st_mutex_t));
|
||||
if (lock) {
|
||||
ST_INIT_CLIST(&lock->wait_q);
|
||||
lock->owner = NULL;
|
||||
}
|
||||
|
||||
return lock;
|
||||
}
|
||||
|
||||
|
||||
int st_mutex_destroy(_st_mutex_t *lock)
|
||||
{
|
||||
if (lock->owner != NULL || lock->wait_q.next != &lock->wait_q) {
|
||||
errno = EBUSY;
|
||||
return -1;
|
||||
}
|
||||
|
||||
free(lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int st_mutex_lock(_st_mutex_t *lock)
|
||||
{
|
||||
_st_thread_t *me = _ST_CURRENT_THREAD();
|
||||
|
||||
if (me->flags & _ST_FL_INTERRUPT) {
|
||||
me->flags &= ~_ST_FL_INTERRUPT;
|
||||
errno = EINTR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (lock->owner == NULL) {
|
||||
/* Got the mutex */
|
||||
lock->owner = me;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lock->owner == me) {
|
||||
errno = EDEADLK;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Put caller thread on the mutex's wait queue */
|
||||
me->state = _ST_ST_LOCK_WAIT;
|
||||
ST_APPEND_LINK(&me->wait_links, &lock->wait_q);
|
||||
|
||||
_ST_SWITCH_CONTEXT(me);
|
||||
|
||||
ST_REMOVE_LINK(&me->wait_links);
|
||||
|
||||
if ((me->flags & _ST_FL_INTERRUPT) && lock->owner != me) {
|
||||
me->flags &= ~_ST_FL_INTERRUPT;
|
||||
errno = EINTR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int st_mutex_unlock(_st_mutex_t *lock)
|
||||
{
|
||||
_st_thread_t *thread;
|
||||
_st_clist_t *q;
|
||||
|
||||
if (lock->owner != _ST_CURRENT_THREAD()) {
|
||||
errno = EPERM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (q = lock->wait_q.next; q != &lock->wait_q; q = q->next) {
|
||||
thread = _ST_THREAD_WAITQ_PTR(q);
|
||||
if (thread->state == _ST_ST_LOCK_WAIT) {
|
||||
lock->owner = thread;
|
||||
/* Make thread runnable */
|
||||
thread->state = _ST_ST_RUNNABLE;
|
||||
_ST_ADD_RUNQ(thread);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* No threads waiting on this mutex */
|
||||
lock->owner = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int st_mutex_trylock(_st_mutex_t *lock)
|
||||
{
|
||||
if (lock->owner != NULL) {
|
||||
errno = EBUSY;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Got the mutex */
|
||||
lock->owner = _ST_CURRENT_THREAD();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue