merged sys and io to si

This commit is contained in:
2016-04-28 14:33:10 +00:00
parent 3c5b45571e
commit 49d3dcfeda
50 changed files with 147 additions and 78 deletions

40
qse/lib/si/Makefile.am Normal file
View File

@ -0,0 +1,40 @@
AUTOMAKE_OPTIONS = nostdinc
AM_CPPFLAGS = \
-I$(top_builddir)/include \
-I$(top_srcdir)/include
lib_LTLIBRARIES = libqsesi.la
libqsesi_la_SOURCES = \
aio-prv.h \
aio.c \
aio-pro.c \
aio-sck.c \
aio-tmr.c \
cnd.c \
fio.c \
intr.c \
mtx.c \
mux.c \
nwio.c \
pio.c \
rwl.c \
sio.c \
task.c \
thr.c \
thr.h \
tio.c
libqsesi_la_CFLAGS = $(PTHREAD_CFLAGS)
libqsesi_la_LDFLAGS = -L../cmn -version-info 1:0:0 -no-undefined
libqsesi_la_LIBADD = -lqsecmn $(PTHREAD_LIBS)
if ENABLE_CXX
lib_LTLIBRARIES += libqsesixx.la
libqsesixx_la_SOURCES = \
SocketAddress.cpp \
Socket.cpp
libqsesixx_la_LDFLAGS = -L. -L../cmn -version-info 1:0:0 -no-undefined
libqsesixx_la_LIBADD = -lqsecmnxx -lqsecmn
endif

830
qse/lib/si/Makefile.in Normal file
View File

@ -0,0 +1,830 @@
# Makefile.in generated by automake 1.14.1 from Makefile.am.
# @configure_input@
# Copyright (C) 1994-2013 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
@SET_MAKE@
VPATH = @srcdir@
am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
am__make_running_with_option = \
case $${target_option-} in \
?) ;; \
*) echo "am__make_running_with_option: internal error: invalid" \
"target option '$${target_option-}' specified" >&2; \
exit 1;; \
esac; \
has_opt=no; \
sane_makeflags=$$MAKEFLAGS; \
if $(am__is_gnu_make); then \
sane_makeflags=$$MFLAGS; \
else \
case $$MAKEFLAGS in \
*\\[\ \ ]*) \
bs=\\; \
sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
| sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
esac; \
fi; \
skip_next=no; \
strip_trailopt () \
{ \
flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
}; \
for flg in $$sane_makeflags; do \
test $$skip_next = yes && { skip_next=no; continue; }; \
case $$flg in \
*=*|--*) continue;; \
-*I) strip_trailopt 'I'; skip_next=yes;; \
-*I?*) strip_trailopt 'I';; \
-*O) strip_trailopt 'O'; skip_next=yes;; \
-*O?*) strip_trailopt 'O';; \
-*l) strip_trailopt 'l'; skip_next=yes;; \
-*l?*) strip_trailopt 'l';; \
-[dEDm]) skip_next=yes;; \
-[JT]) skip_next=yes;; \
esac; \
case $$flg in \
*$$target_option*) has_opt=yes; break;; \
esac; \
done; \
test $$has_opt = yes
am__make_dryrun = (target_option=n; $(am__make_running_with_option))
am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
pkgdatadir = $(datadir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
pkglibexecdir = $(libexecdir)/@PACKAGE@
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
install_sh_DATA = $(install_sh) -c -m 644
install_sh_PROGRAM = $(install_sh) -c
install_sh_SCRIPT = $(install_sh) -c
INSTALL_HEADER = $(INSTALL_DATA)
transform = $(program_transform_name)
NORMAL_INSTALL = :
PRE_INSTALL = :
POST_INSTALL = :
NORMAL_UNINSTALL = :
PRE_UNINSTALL = :
POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
@ENABLE_CXX_TRUE@am__append_1 = libqsesysxx.la
subdir = lib/sys
DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
$(top_srcdir)/ac/depcomp
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/argz.m4 \
$(top_srcdir)/m4/ax_check_sign.m4 \
$(top_srcdir)/m4/ax_cxx_namespace.m4 \
$(top_srcdir)/m4/ax_numval.m4 $(top_srcdir)/m4/ax_pthread.m4 \
$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltdl.m4 \
$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
$(top_srcdir)/m4/lx_find_mpi.m4 $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
mkinstalldirs = $(install_sh) -d
CONFIG_HEADER = $(top_builddir)/include/qse/config.h
CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
am__vpath_adj = case $$p in \
$(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
*) f=$$p;; \
esac;
am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
am__install_max = 40
am__nobase_strip_setup = \
srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
am__nobase_strip = \
for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
am__nobase_list = $(am__nobase_strip_setup); \
for p in $$list; do echo "$$p $$p"; done | \
sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
$(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
if (++n[$$2] == $(am__install_max)) \
{ print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
END { for (dir in files) print dir, files[dir] }'
am__base_list = \
sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
am__uninstall_files_from_dir = { \
test -z "$$files" \
|| { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
|| { echo " ( cd '$$dir' && rm -f" $$files ")"; \
$(am__cd) "$$dir" && rm -f $$files; }; \
}
am__installdirs = "$(DESTDIR)$(libdir)"
LTLIBRARIES = $(lib_LTLIBRARIES)
am__DEPENDENCIES_1 =
libqsesys_la_DEPENDENCIES = $(am__DEPENDENCIES_1)
am_libqsesys_la_OBJECTS = libqsesys_la-cnd.lo libqsesys_la-intr.lo \
libqsesys_la-mtx.lo libqsesys_la-mux.lo libqsesys_la-rwl.lo \
libqsesys_la-task.lo libqsesys_la-thr.lo
libqsesys_la_OBJECTS = $(am_libqsesys_la_OBJECTS)
AM_V_lt = $(am__v_lt_@AM_V@)
am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
am__v_lt_0 = --silent
am__v_lt_1 =
libqsesys_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(libqsesys_la_CFLAGS) \
$(CFLAGS) $(libqsesys_la_LDFLAGS) $(LDFLAGS) -o $@
libqsesysxx_la_DEPENDENCIES =
am__libqsesysxx_la_SOURCES_DIST = SocketAddress.cpp Socket.cpp
@ENABLE_CXX_TRUE@am_libqsesysxx_la_OBJECTS = SocketAddress.lo \
@ENABLE_CXX_TRUE@ Socket.lo
libqsesysxx_la_OBJECTS = $(am_libqsesysxx_la_OBJECTS)
libqsesysxx_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \
$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \
$(AM_CXXFLAGS) $(CXXFLAGS) $(libqsesysxx_la_LDFLAGS) \
$(LDFLAGS) -o $@
@ENABLE_CXX_TRUE@am_libqsesysxx_la_rpath = -rpath $(libdir)
AM_V_P = $(am__v_P_@AM_V@)
am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
am__v_P_0 = false
am__v_P_1 = :
AM_V_GEN = $(am__v_GEN_@AM_V@)
am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
am__v_GEN_0 = @echo " GEN " $@;
am__v_GEN_1 =
AM_V_at = $(am__v_at_@AM_V@)
am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
am__v_at_0 = @
am__v_at_1 =
DEFAULT_INCLUDES =
depcomp = $(SHELL) $(top_srcdir)/ac/depcomp
am__depfiles_maybe = depfiles
am__mv = mv -f
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
$(AM_CFLAGS) $(CFLAGS)
AM_V_CC = $(am__v_CC_@AM_V@)
am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
am__v_CC_0 = @echo " CC " $@;
am__v_CC_1 =
CCLD = $(CC)
LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
$(AM_LDFLAGS) $(LDFLAGS) -o $@
AM_V_CCLD = $(am__v_CCLD_@AM_V@)
am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
am__v_CCLD_0 = @echo " CCLD " $@;
am__v_CCLD_1 =
CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \
$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
$(AM_CXXFLAGS) $(CXXFLAGS)
AM_V_CXX = $(am__v_CXX_@AM_V@)
am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@)
am__v_CXX_0 = @echo " CXX " $@;
am__v_CXX_1 =
CXXLD = $(CXX)
CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
$(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
AM_V_CXXLD = $(am__v_CXXLD_@AM_V@)
am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@)
am__v_CXXLD_0 = @echo " CXXLD " $@;
am__v_CXXLD_1 =
SOURCES = $(libqsesys_la_SOURCES) $(libqsesysxx_la_SOURCES)
DIST_SOURCES = $(libqsesys_la_SOURCES) \
$(am__libqsesysxx_la_SOURCES_DIST)
am__can_run_installinfo = \
case $$AM_UPDATE_INFO_DIR in \
n|no|NO) false;; \
*) (install-info --version) >/dev/null 2>&1;; \
esac
am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
# Read a list of newline-separated strings from the standard input,
# and print each of them once, without duplicates. Input order is
# *not* preserved.
am__uniquify_input = $(AWK) '\
BEGIN { nonempty = 0; } \
{ items[$$0] = 1; nonempty = 1; } \
END { if (nonempty) { for (i in items) print i; }; } \
'
# Make sure the list of sources is unique. This is necessary because,
# e.g., the same source file might be shared among _SOURCES variables
# for different programs/libraries.
am__define_uniq_tagged_files = \
list='$(am__tagged_files)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | $(am__uniquify_input)`
ETAGS = etags
CTAGS = ctags
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
ACLOCAL = @ACLOCAL@
AMTAR = @AMTAR@
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
AR = @AR@
ARGZ_H = @ARGZ_H@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
AWK = @AWK@
BUILD_MODE = @BUILD_MODE@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CFLAGS = @CFLAGS@
CHAR_MODE = @CHAR_MODE@
CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
CXX = @CXX@
CXXCPP = @CXXCPP@
CXXDEPMODE = @CXXDEPMODE@
CXXFLAGS = @CXXFLAGS@
CYGPATH_W = @CYGPATH_W@
DEFS = @DEFS@
DEPDIR = @DEPDIR@
DLLTOOL = @DLLTOOL@
DSYMUTIL = @DSYMUTIL@
DUMPBIN = @DUMPBIN@
ECHO = @ECHO@
ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
EXEEXT = @EXEEXT@
FGREP = @FGREP@
GREP = @GREP@
HAVE_CXX = @HAVE_CXX@
INCLTDL = @INCLTDL@
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
LD = @LD@
LDFLAGS = @LDFLAGS@
LIBADD_DL = @LIBADD_DL@
LIBADD_DLD_LINK = @LIBADD_DLD_LINK@
LIBADD_DLOPEN = @LIBADD_DLOPEN@
LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@
LIBLTDL = @LIBLTDL@
LIBM = @LIBM@
LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LIBTOOL = @LIBTOOL@
LIBTOOL_DEPS = @LIBTOOL_DEPS@
LIPO = @LIPO@
LN_S = @LN_S@
LTDLDEPS = @LTDLDEPS@
LTDLINCL = @LTDLINCL@
LTDLOPEN = @LTDLOPEN@
LTLIBOBJS = @LTLIBOBJS@
LT_CONFIG_H = @LT_CONFIG_H@
LT_DLLOADERS = @LT_DLLOADERS@
LT_DLPREOPEN = @LT_DLPREOPEN@
MAKEINFO = @MAKEINFO@
MANIFEST_TOOL = @MANIFEST_TOOL@
MKDIR_P = @MKDIR_P@
MPICC = @MPICC@
MPI_CFLAGS = @MPI_CFLAGS@
MPI_CLDFLAGS = @MPI_CLDFLAGS@
NM = @NM@
NMEDIT = @NMEDIT@
OBJDUMP = @OBJDUMP@
OBJEXT = @OBJEXT@
OTOOL = @OTOOL@
OTOOL64 = @OTOOL64@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
PACKAGE_NAME = @PACKAGE_NAME@
PACKAGE_STRING = @PACKAGE_STRING@
PACKAGE_TARNAME = @PACKAGE_TARNAME@
PACKAGE_URL = @PACKAGE_URL@
PACKAGE_VERSION = @PACKAGE_VERSION@
PACKAGE_VERSION_MAJOR = @PACKAGE_VERSION_MAJOR@
PACKAGE_VERSION_MINOR = @PACKAGE_VERSION_MINOR@
PACKAGE_VERSION_PATCH = @PACKAGE_VERSION_PATCH@
PATH_SEPARATOR = @PATH_SEPARATOR@
PTHREAD_CC = @PTHREAD_CC@
PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
PTHREAD_LIBS = @PTHREAD_LIBS@
QSE_PROJECT_AUTHOR = @QSE_PROJECT_AUTHOR@
QSE_PROJECT_URL = @QSE_PROJECT_URL@
QSE_SIZEOF_CHAR = @QSE_SIZEOF_CHAR@
QSE_SIZEOF_DOUBLE = @QSE_SIZEOF_DOUBLE@
QSE_SIZEOF_FLOAT = @QSE_SIZEOF_FLOAT@
QSE_SIZEOF_INT = @QSE_SIZEOF_INT@
QSE_SIZEOF_LONG = @QSE_SIZEOF_LONG@
QSE_SIZEOF_LONG_DOUBLE = @QSE_SIZEOF_LONG_DOUBLE@
QSE_SIZEOF_LONG_LONG = @QSE_SIZEOF_LONG_LONG@
QSE_SIZEOF_OFF64_T = @QSE_SIZEOF_OFF64_T@
QSE_SIZEOF_OFF_T = @QSE_SIZEOF_OFF_T@
QSE_SIZEOF_SHORT = @QSE_SIZEOF_SHORT@
QSE_SIZEOF_VOID_P = @QSE_SIZEOF_VOID_P@
QSE_SIZEOF_WCHAR_T = @QSE_SIZEOF_WCHAR_T@
QUADMATH_LIBS = @QUADMATH_LIBS@
RANLIB = @RANLIB@
RM = @RM@
RMDIR = @RMDIR@
SED = @SED@
SENDFILE_LIBS = @SENDFILE_LIBS@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
SOCKET_LIBS = @SOCKET_LIBS@
SSL_LIBS = @SSL_LIBS@
STRIP = @STRIP@
TRUE = @TRUE@
UCI_LIBS = @UCI_LIBS@
UNICOWS_LIBS = @UNICOWS_LIBS@
VERSION = @VERSION@
abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
abs_top_builddir = @abs_top_builddir@
abs_top_srcdir = @abs_top_srcdir@
ac_ct_AR = @ac_ct_AR@
ac_ct_CC = @ac_ct_CC@
ac_ct_CXX = @ac_ct_CXX@
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
am__include = @am__include@
am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
am__tar = @am__tar@
am__untar = @am__untar@
ax_pthread_config = @ax_pthread_config@
bindir = @bindir@
build = @build@
build_alias = @build_alias@
build_cpu = @build_cpu@
build_os = @build_os@
build_vendor = @build_vendor@
builddir = @builddir@
datadir = @datadir@
datarootdir = @datarootdir@
docdir = @docdir@
dvidir = @dvidir@
exec_prefix = @exec_prefix@
host = @host@
host_alias = @host_alias@
host_cpu = @host_cpu@
host_os = @host_os@
host_vendor = @host_vendor@
htmldir = @htmldir@
includedir = @includedir@
infodir = @infodir@
install_sh = @install_sh@
libdir = @libdir@
libexecdir = @libexecdir@
localedir = @localedir@
localstatedir = @localstatedir@
ltdl_LIBOBJS = @ltdl_LIBOBJS@
ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@
mandir = @mandir@
mkdir_p = @mkdir_p@
oldincludedir = @oldincludedir@
pdfdir = @pdfdir@
prefix = @prefix@
program_transform_name = @program_transform_name@
psdir = @psdir@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
subdirs = @subdirs@
sys_symbol_underscore = @sys_symbol_underscore@
sysconfdir = @sysconfdir@
target_alias = @target_alias@
top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
AUTOMAKE_OPTIONS = nostdinc
AM_CPPFLAGS = \
-I$(top_builddir)/include \
-I$(top_srcdir)/include
lib_LTLIBRARIES = libqsesys.la $(am__append_1)
libqsesys_la_SOURCES = \
cnd.c \
intr.c \
mtx.c \
mux.c \
rwl.c \
task.c \
thr.c \
thr.h
libqsesys_la_CFLAGS = $(PTHREAD_CFLAGS)
libqsesys_la_LDFLAGS = -L../cmn -version-info 1:0:0 -no-undefined
libqsesys_la_LIBADD = -lqsecmn $(PTHREAD_LIBS)
@ENABLE_CXX_TRUE@libqsesysxx_la_SOURCES = \
@ENABLE_CXX_TRUE@ SocketAddress.cpp \
@ENABLE_CXX_TRUE@ Socket.cpp
@ENABLE_CXX_TRUE@libqsesysxx_la_LDFLAGS = -L. -L../cmn -version-info 1:0:0 -no-undefined
@ENABLE_CXX_TRUE@libqsesysxx_la_LIBADD = -lqsecmnxx -lqsecmn
all: all-am
.SUFFIXES:
.SUFFIXES: .c .cpp .lo .o .obj
$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
@for dep in $?; do \
case '$(am__configure_deps)' in \
*$$dep*) \
( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
&& { if test -f $@; then exit 0; else break; fi; }; \
exit 1;; \
esac; \
done; \
echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign lib/sys/Makefile'; \
$(am__cd) $(top_srcdir) && \
$(AUTOMAKE) --foreign lib/sys/Makefile
.PRECIOUS: Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
*) \
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
esac;
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(top_srcdir)/configure: $(am__configure_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(ACLOCAL_M4): $(am__aclocal_m4_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(am__aclocal_m4_deps):
install-libLTLIBRARIES: $(lib_LTLIBRARIES)
@$(NORMAL_INSTALL)
@list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
list2=; for p in $$list; do \
if test -f $$p; then \
list2="$$list2 $$p"; \
else :; fi; \
done; \
test -z "$$list2" || { \
echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \
$(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \
echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \
$(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \
}
uninstall-libLTLIBRARIES:
@$(NORMAL_UNINSTALL)
@list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
for p in $$list; do \
$(am__strip_dir) \
echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \
$(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \
done
clean-libLTLIBRARIES:
-test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
@list='$(lib_LTLIBRARIES)'; \
locs=`for p in $$list; do echo $$p; done | \
sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
sort -u`; \
test -z "$$locs" || { \
echo rm -f $${locs}; \
rm -f $${locs}; \
}
libqsesys.la: $(libqsesys_la_OBJECTS) $(libqsesys_la_DEPENDENCIES) $(EXTRA_libqsesys_la_DEPENDENCIES)
$(AM_V_CCLD)$(libqsesys_la_LINK) -rpath $(libdir) $(libqsesys_la_OBJECTS) $(libqsesys_la_LIBADD) $(LIBS)
libqsesysxx.la: $(libqsesysxx_la_OBJECTS) $(libqsesysxx_la_DEPENDENCIES) $(EXTRA_libqsesysxx_la_DEPENDENCIES)
$(AM_V_CXXLD)$(libqsesysxx_la_LINK) $(am_libqsesysxx_la_rpath) $(libqsesysxx_la_OBJECTS) $(libqsesysxx_la_LIBADD) $(LIBS)
mostlyclean-compile:
-rm -f *.$(OBJEXT)
distclean-compile:
-rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Socket.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SocketAddress.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libqsesys_la-cnd.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libqsesys_la-intr.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libqsesys_la-mtx.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libqsesys_la-mux.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libqsesys_la-rwl.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libqsesys_la-task.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libqsesys_la-thr.Plo@am__quote@
.c.o:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
.c.obj:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
.c.lo:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
libqsesys_la-cnd.lo: cnd.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libqsesys_la_CFLAGS) $(CFLAGS) -MT libqsesys_la-cnd.lo -MD -MP -MF $(DEPDIR)/libqsesys_la-cnd.Tpo -c -o libqsesys_la-cnd.lo `test -f 'cnd.c' || echo '$(srcdir)/'`cnd.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libqsesys_la-cnd.Tpo $(DEPDIR)/libqsesys_la-cnd.Plo
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cnd.c' object='libqsesys_la-cnd.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libqsesys_la_CFLAGS) $(CFLAGS) -c -o libqsesys_la-cnd.lo `test -f 'cnd.c' || echo '$(srcdir)/'`cnd.c
libqsesys_la-intr.lo: intr.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libqsesys_la_CFLAGS) $(CFLAGS) -MT libqsesys_la-intr.lo -MD -MP -MF $(DEPDIR)/libqsesys_la-intr.Tpo -c -o libqsesys_la-intr.lo `test -f 'intr.c' || echo '$(srcdir)/'`intr.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libqsesys_la-intr.Tpo $(DEPDIR)/libqsesys_la-intr.Plo
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='intr.c' object='libqsesys_la-intr.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libqsesys_la_CFLAGS) $(CFLAGS) -c -o libqsesys_la-intr.lo `test -f 'intr.c' || echo '$(srcdir)/'`intr.c
libqsesys_la-mtx.lo: mtx.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libqsesys_la_CFLAGS) $(CFLAGS) -MT libqsesys_la-mtx.lo -MD -MP -MF $(DEPDIR)/libqsesys_la-mtx.Tpo -c -o libqsesys_la-mtx.lo `test -f 'mtx.c' || echo '$(srcdir)/'`mtx.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libqsesys_la-mtx.Tpo $(DEPDIR)/libqsesys_la-mtx.Plo
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mtx.c' object='libqsesys_la-mtx.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libqsesys_la_CFLAGS) $(CFLAGS) -c -o libqsesys_la-mtx.lo `test -f 'mtx.c' || echo '$(srcdir)/'`mtx.c
libqsesys_la-mux.lo: mux.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libqsesys_la_CFLAGS) $(CFLAGS) -MT libqsesys_la-mux.lo -MD -MP -MF $(DEPDIR)/libqsesys_la-mux.Tpo -c -o libqsesys_la-mux.lo `test -f 'mux.c' || echo '$(srcdir)/'`mux.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libqsesys_la-mux.Tpo $(DEPDIR)/libqsesys_la-mux.Plo
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mux.c' object='libqsesys_la-mux.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libqsesys_la_CFLAGS) $(CFLAGS) -c -o libqsesys_la-mux.lo `test -f 'mux.c' || echo '$(srcdir)/'`mux.c
libqsesys_la-rwl.lo: rwl.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libqsesys_la_CFLAGS) $(CFLAGS) -MT libqsesys_la-rwl.lo -MD -MP -MF $(DEPDIR)/libqsesys_la-rwl.Tpo -c -o libqsesys_la-rwl.lo `test -f 'rwl.c' || echo '$(srcdir)/'`rwl.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libqsesys_la-rwl.Tpo $(DEPDIR)/libqsesys_la-rwl.Plo
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='rwl.c' object='libqsesys_la-rwl.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libqsesys_la_CFLAGS) $(CFLAGS) -c -o libqsesys_la-rwl.lo `test -f 'rwl.c' || echo '$(srcdir)/'`rwl.c
libqsesys_la-task.lo: task.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libqsesys_la_CFLAGS) $(CFLAGS) -MT libqsesys_la-task.lo -MD -MP -MF $(DEPDIR)/libqsesys_la-task.Tpo -c -o libqsesys_la-task.lo `test -f 'task.c' || echo '$(srcdir)/'`task.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libqsesys_la-task.Tpo $(DEPDIR)/libqsesys_la-task.Plo
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='task.c' object='libqsesys_la-task.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libqsesys_la_CFLAGS) $(CFLAGS) -c -o libqsesys_la-task.lo `test -f 'task.c' || echo '$(srcdir)/'`task.c
libqsesys_la-thr.lo: thr.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libqsesys_la_CFLAGS) $(CFLAGS) -MT libqsesys_la-thr.lo -MD -MP -MF $(DEPDIR)/libqsesys_la-thr.Tpo -c -o libqsesys_la-thr.lo `test -f 'thr.c' || echo '$(srcdir)/'`thr.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libqsesys_la-thr.Tpo $(DEPDIR)/libqsesys_la-thr.Plo
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='thr.c' object='libqsesys_la-thr.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libqsesys_la_CFLAGS) $(CFLAGS) -c -o libqsesys_la-thr.lo `test -f 'thr.c' || echo '$(srcdir)/'`thr.c
.cpp.o:
@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $<
.cpp.obj:
@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
.cpp.lo:
@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $<
mostlyclean-libtool:
-rm -f *.lo
clean-libtool:
-rm -rf .libs _libs
ID: $(am__tagged_files)
$(am__define_uniq_tagged_files); mkid -fID $$unique
tags: tags-am
TAGS: tags
tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
set x; \
here=`pwd`; \
$(am__define_uniq_tagged_files); \
shift; \
if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
test -n "$$unique" || unique=$$empty_fix; \
if test $$# -gt 0; then \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
"$$@" $$unique; \
else \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
$$unique; \
fi; \
fi
ctags: ctags-am
CTAGS: ctags
ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
$(am__define_uniq_tagged_files); \
test -z "$(CTAGS_ARGS)$$unique" \
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
$$unique
GTAGS:
here=`$(am__cd) $(top_builddir) && pwd` \
&& $(am__cd) $(top_srcdir) \
&& gtags -i $(GTAGS_ARGS) "$$here"
cscopelist: cscopelist-am
cscopelist-am: $(am__tagged_files)
list='$(am__tagged_files)'; \
case "$(srcdir)" in \
[\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
*) sdir=$(subdir)/$(srcdir) ;; \
esac; \
for i in $$list; do \
if test -f "$$i"; then \
echo "$(subdir)/$$i"; \
else \
echo "$$sdir/$$i"; \
fi; \
done >> $(top_builddir)/cscope.files
distclean-tags:
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
distdir: $(DISTFILES)
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
list='$(DISTFILES)'; \
dist_files=`for file in $$list; do echo $$file; done | \
sed -e "s|^$$srcdirstrip/||;t" \
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
case $$dist_files in \
*/*) $(MKDIR_P) `echo "$$dist_files" | \
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
sort -u` ;; \
esac; \
for file in $$dist_files; do \
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
if test -d $$d/$$file; then \
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
if test -d "$(distdir)/$$file"; then \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
else \
test -f "$(distdir)/$$file" \
|| cp -p $$d/$$file "$(distdir)/$$file" \
|| exit 1; \
fi; \
done
check-am: all-am
check: check-am
all-am: Makefile $(LTLIBRARIES)
installdirs:
for dir in "$(DESTDIR)$(libdir)"; do \
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
done
install: install-am
install-exec: install-exec-am
install-data: install-data-am
uninstall: uninstall-am
install-am: all-am
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
installcheck: installcheck-am
install-strip:
if test -z '$(STRIP)'; then \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
install; \
else \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
fi
mostlyclean-generic:
clean-generic:
distclean-generic:
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
maintainer-clean-generic:
@echo "This command is intended for maintainers to use"
@echo "it deletes files that may require special tools to rebuild."
clean: clean-am
clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
mostlyclean-am
distclean: distclean-am
-rm -rf ./$(DEPDIR)
-rm -f Makefile
distclean-am: clean-am distclean-compile distclean-generic \
distclean-tags
dvi: dvi-am
dvi-am:
html: html-am
html-am:
info: info-am
info-am:
install-data-am:
install-dvi: install-dvi-am
install-dvi-am:
install-exec-am: install-libLTLIBRARIES
install-html: install-html-am
install-html-am:
install-info: install-info-am
install-info-am:
install-man:
install-pdf: install-pdf-am
install-pdf-am:
install-ps: install-ps-am
install-ps-am:
installcheck-am:
maintainer-clean: maintainer-clean-am
-rm -rf ./$(DEPDIR)
-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-generic
mostlyclean: mostlyclean-am
mostlyclean-am: mostlyclean-compile mostlyclean-generic \
mostlyclean-libtool
pdf: pdf-am
pdf-am:
ps: ps-am
ps-am:
uninstall-am: uninstall-libLTLIBRARIES
.MAKE: install-am install-strip
.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
clean-libLTLIBRARIES clean-libtool cscopelist-am ctags \
ctags-am distclean distclean-compile distclean-generic \
distclean-libtool distclean-tags distdir dvi dvi-am html \
html-am info info-am install install-am install-data \
install-data-am install-dvi install-dvi-am install-exec \
install-exec-am install-html install-html-am install-info \
install-info-am install-libLTLIBRARIES install-man install-pdf \
install-pdf-am install-ps install-ps-am install-strip \
installcheck installcheck-am installdirs maintainer-clean \
maintainer-clean-generic mostlyclean mostlyclean-compile \
mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
tags tags-am uninstall uninstall-am uninstall-libLTLIBRARIES
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:

71
qse/lib/si/Socket.cpp Normal file
View File

@ -0,0 +1,71 @@
/*
* $Id$
*
Copyright (c) 2006-2014 Chung, Hyung-Hwan. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <qse/si/Socket.hpp>
/////////////////////////////////
QSE_BEGIN_NAMESPACE(QSE)
/////////////////////////////////
Socket::Socket (): handle(QSE_INVALID_SCKHND)
{
}
Socket::~Socket ()
{
this->close ();
}
void Socket::close ()
{
if (this->handle != QSE_INVALID_SCKHND)
{
qse_closesckhnd (this->handle);
this->handle = QSE_INVALID_SCKHND;
}
}
//int Socket::open (int domain, int type, int protocol)
//{
//}
int Socket::connect (const SocketAddress& target)
{
if (this->handle == QSE_INVALID_SCKHND)
{
//::socket (target.getFamily(), this->type, 0);
}
}
int Socket::beginConnect (const SocketAddress &target)
{
}
/////////////////////////////////
QSE_END_NAMESPACE(QSE)
/////////////////////////////////

View File

@ -0,0 +1,220 @@
/*
* $Id$
*
Copyright (c) 2006-2014 Chung, Hyung-Hwan. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <qse/si/SocketAddress.hpp>
#include "../cmn/mem.h"
#if defined(_WIN32)
# include <winsock2.h>
# include <ws2tcpip.h> /* sockaddr_in6 */
# include <windows.h>
# undef AF_UNIX
# if defined(__WATCOMC__) && (__WATCOMC__ < 1200)
/* the header files shipped with watcom 11 doesn't contain
* proper inet6 support. note using the compiler version
* in the contidional isn't that good idea since you
* can use newer header files with this old compiler.
* never mind it for the time being.
*/
# undef AF_INET6
# endif
#elif defined(__OS2__)
# include <types.h>
# include <sys/socket.h>
# include <netinet/in.h>
/* though AF_INET6 is defined, there is no support
* for it. so undefine it */
# undef AF_INET6
# undef AF_UNIX
# pragma library("tcpip32.lib")
#elif defined(__DOS__)
# include <tcp.h> /* watt-32 */
# undef AF_UNIX
#else
# if defined(HAVE_SYS_TYPES_H)
# include <sys/types.h>
# endif
# include <sys/socket.h>
# include <netinet/in.h>
# if defined(HAVE_SYS_UN_H)
# include <sys/un.h>
# endif
# if defined(QSE_SIZEOF_STRUCT_SOCKADDR_IN6) && (QSE_SIZEOF_STRUCT_SOCKADDR_IN6 <= 0)
# undef AF_INET6
# endif
# if defined(QSE_SIZEOF_STRUCT_SOCKADDR_UN) && (QSE_SIZEOF_STRUCT_SOCKADDR_UN <= 0)
# undef AF_UNIX
# endif
#endif
#if defined(AF_INET)
# define FAMILY(x) (((struct sockaddr_in*)(x))->sin_family)
#elif defined(AF_INET6)
# define FAMILY(x) (((struct sockaddr_in6*)(x))->sin6_family)
#elif defined(AF_UNIX)
# define FAMILY(x) (((struct sockaddr_un*)(x))->sun_family)
#else
# define FAMILY(x) (-1)
#endif
/////////////////////////////////
QSE_BEGIN_NAMESPACE(QSE)
/////////////////////////////////
SocketAddress::SocketAddress ()
{
QSE_MEMSET (&this->skad, 0, QSE_SIZEOF(this->skad));
}
SocketAddress::SocketAddress (int family)
{
QSE_MEMSET (&this->skad, 0, QSE_SIZEOF(this->skad));
FAMILY(&this->skad) = family;
}
SocketAddress::SocketAddress (const qse_skad_t* skad)
{
this->set (skad);
}
SocketAddress::SocketAddress (const qse_nwad_t* nwad)
{
this->set (nwad);
}
SocketAddress::SocketAddress (const struct sockaddr* ptr, int len)
{
if (this->set (ptr, len) <= -1)
{
QSE_MEMSET (&this->skad, 0, QSE_SIZEOF(this->skad));
}
}
int SocketAddress::getFamily () const
{
return FAMILY(&this->skad);
//return qse_skadfamily (&this->skad);
}
void SocketAddress::setIpaddr (const qse_ip4ad_t* ipaddr)
{
#if defined(AF_INET)
if (FAMILY(&this->skad) == AF_INET)
{
struct sockaddr_in* v4 = (struct sockaddr_in*)&this->skad;
QSE_MEMCPY (&v4->sin_addr, ipaddr, QSE_SIZEOF(*ipaddr));
}
#endif
}
void SocketAddress::setIpaddr (const qse_ip6ad_t* ipaddr)
{
#if defined(AF_INET6)
if (FAMILY(&this->skad) == AF_INET6)
{
struct sockaddr_in6* v6 = (struct sockaddr_in6*)&this->skad;
QSE_MEMCPY (&v6->sin6_addr, ipaddr, QSE_SIZEOF(*ipaddr));
}
#endif
}
qse_uint16_t SocketAddress::getPort () const
{
switch (FAMILY(&this->skad))
{
#if defined(AF_INET)
case AF_INET:
{
struct sockaddr_in* v4 = (struct sockaddr_in*)&this->skad;
return v4->sin_port;
}
#endif
#if defined(AF_INET6)
case AF_INET6:
{
struct sockaddr_in6* v6 = (struct sockaddr_in6*)&this->skad;
return v6->sin6_port;
}
#endif
}
return 0;
}
void SocketAddress::setPort (qse_uint16_t port)
{
switch (FAMILY(&this->skad))
{
#if defined(AF_INET)
case AF_INET:
{
struct sockaddr_in* v4 = (struct sockaddr_in*)&this->skad;
v4->sin_port = port;
break;
}
#endif
#if defined(AF_INET6)
case AF_INET6:
{
struct sockaddr_in6* v6 = (struct sockaddr_in6*)&this->skad;
v6->sin6_port = port;
break;
}
#endif
}
}
int SocketAddress::set (const qse_skad_t* skad)
{
this->skad = *skad;
return 0;
}
int SocketAddress::set (const qse_nwad_t* nwad)
{
return qse_nwadtoskad (nwad, &this->skad);
}
int SocketAddress::set (const struct sockaddr* ptr, int len)
{
int exp_size = qse_skadsize((const qse_skad_t*)ptr);
if (len < exp_size) return -1;
QSE_MEMCPY (&this->skad, ptr, exp_size);
return 0;
}
/////////////////////////////////
QSE_END_NAMESPACE(QSE)
/////////////////////////////////

852
qse/lib/si/aio-pro.c Normal file
View File

@ -0,0 +1,852 @@
/*
* $Id$
*
Copyright (c) 2006-2016 Chung, Hyung-Hwan. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WAfRRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <qse/si/aio-pro.h>
#include "aio-prv.h"
#include <qse/cmn/str.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/wait.h>
/* ========================================================================= */
struct slave_info_t
{
qse_aio_dev_pro_make_t* mi;
qse_aio_syshnd_t pfd;
int dev_capa;
qse_aio_dev_pro_sid_t id;
};
typedef struct slave_info_t slave_info_t;
static qse_aio_dev_pro_slave_t* make_slave (qse_aio_t* aio, slave_info_t* si);
/* ========================================================================= */
struct param_t
{
qse_mchar_t* mcmd;
qse_mchar_t* fixed_argv[4];
qse_mchar_t** argv;
};
typedef struct param_t param_t;
static void free_param (qse_aio_t* aio, param_t* param)
{
if (param->argv && param->argv != param->fixed_argv)
QSE_MMGR_FREE (aio->mmgr, param->argv);
if (param->mcmd) QSE_MMGR_FREE (aio->mmgr, param->mcmd);
QSE_MEMSET (param, 0, QSE_SIZEOF(*param));
}
static int make_param (qse_aio_t* aio, const qse_mchar_t* cmd, int flags, param_t* param)
{
int fcnt = 0;
qse_mchar_t* mcmd = QSE_NULL;
QSE_MEMSET (param, 0, QSE_SIZEOF(*param));
if (flags & QSE_AIO_DEV_PRO_SHELL)
{
mcmd = (qse_mchar_t*)cmd;
param->argv = param->fixed_argv;
param->argv[0] = QSE_MT("/bin/sh");
param->argv[1] = QSE_MT("-c");
param->argv[2] = mcmd;
param->argv[3] = QSE_NULL;
}
else
{
int i;
qse_mchar_t** argv;
qse_mchar_t* mcmdptr;
mcmd = qse_mbsdup (cmd, aio->mmgr);
if (!mcmd)
{
aio->errnum = QSE_AIO_ENOMEM;
goto oops;
}
fcnt = qse_mbsspl (mcmd, QSE_MT(""), QSE_MT('\"'), QSE_MT('\"'), QSE_MT('\\'));
if (fcnt <= 0)
{
/* no field or an error */
aio->errnum = QSE_AIO_EINVAL;
goto oops;
}
if (fcnt < QSE_COUNTOF(param->fixed_argv))
{
param->argv = param->fixed_argv;
}
else
{
param->argv = QSE_MMGR_ALLOC (aio->mmgr, (fcnt + 1) * QSE_SIZEOF(argv[0]));
if (param->argv == QSE_NULL)
{
aio->errnum = QSE_AIO_ENOMEM;
goto oops;
}
}
mcmdptr = mcmd;
for (i = 0; i < fcnt; i++)
{
param->argv[i] = mcmdptr;
while (*mcmdptr != QSE_MT('\0')) mcmdptr++;
mcmdptr++;
}
param->argv[i] = QSE_NULL;
}
if (mcmd && mcmd != (qse_mchar_t*)cmd) param->mcmd = mcmd;
return 0;
oops:
if (mcmd && mcmd != cmd) QSE_MMGR_FREE (aio->mmgr, mcmd);
return -1;
}
static pid_t standard_fork_and_exec (qse_aio_t* aio, int pfds[], int flags, param_t* param)
{
pid_t pid;
pid = fork ();
if (pid == -1)
{
aio->errnum = qse_aio_syserrtoerrnum(errno);
return -1;
}
if (pid == 0)
{
/* slave process */
qse_aio_syshnd_t devnull = QSE_AIO_SYSHND_INVALID;
/* TODO: close all uneeded fds */
if (flags & QSE_AIO_DEV_PRO_WRITEIN)
{
/* slave should read */
close (pfds[1]);
pfds[1] = QSE_AIO_SYSHND_INVALID;
/* let the pipe be standard input */
if (dup2 (pfds[0], 0) <= -1) goto slave_oops;
close (pfds[0]);
pfds[0] = QSE_AIO_SYSHND_INVALID;
}
if (flags & QSE_AIO_DEV_PRO_READOUT)
{
/* slave should write */
close (pfds[2]);
pfds[2] = QSE_AIO_SYSHND_INVALID;
if (dup2(pfds[3], 1) == -1) goto slave_oops;
if (flags & QSE_AIO_DEV_PRO_ERRTOOUT)
{
if (dup2(pfds[3], 2) == -1) goto slave_oops;
}
close (pfds[3]);
pfds[3] = QSE_AIO_SYSHND_INVALID;
}
if (flags & QSE_AIO_DEV_PRO_READERR)
{
close (pfds[4]);
pfds[4] = QSE_AIO_SYSHND_INVALID;
if (dup2(pfds[5], 2) == -1) goto slave_oops;
if (flags & QSE_AIO_DEV_PRO_OUTTOERR)
{
if (dup2(pfds[5], 1) == -1) goto slave_oops;
}
close (pfds[5]);
pfds[5] = QSE_AIO_SYSHND_INVALID;
}
if ((flags & QSE_AIO_DEV_PRO_INTONUL) ||
(flags & QSE_AIO_DEV_PRO_OUTTONUL) ||
(flags & QSE_AIO_DEV_PRO_ERRTONUL))
{
#if defined(O_LARGEFILE)
devnull = open (QSE_MT("/dev/null"), O_RDWR | O_LARGEFILE, 0);
#else
devnull = open (QSE_MT("/dev/null"), O_RDWR, 0);
#endif
if (devnull == QSE_AIO_SYSHND_INVALID) goto slave_oops;
}
execv (param->argv[0], param->argv);
/* if exec fails, free 'param' parameter which is an inherited pointer */
free_param (aio, param);
slave_oops:
if (devnull != QSE_AIO_SYSHND_INVALID) close(devnull);
_exit (128);
}
/* parent process */
return pid;
}
static int dev_pro_make_master (qse_aio_dev_t* dev, void* ctx)
{
qse_aio_dev_pro_t* rdev = (qse_aio_dev_pro_t*)dev;
qse_aio_dev_pro_make_t* info = (qse_aio_dev_pro_make_t*)ctx;
qse_aio_syshnd_t pfds[6];
int i, minidx = -1, maxidx = -1;
param_t param;
pid_t pid;
if (info->flags & QSE_AIO_DEV_PRO_WRITEIN)
{
if (pipe(&pfds[0]) == -1)
{
dev->aio->errnum = qse_aio_syserrtoerrnum(errno);
goto oops;
}
minidx = 0; maxidx = 1;
}
if (info->flags & QSE_AIO_DEV_PRO_READOUT)
{
if (pipe(&pfds[2]) == -1)
{
dev->aio->errnum = qse_aio_syserrtoerrnum(errno);
goto oops;
}
if (minidx == -1) minidx = 2;
maxidx = 3;
}
if (info->flags & QSE_AIO_DEV_PRO_READERR)
{
if (pipe(&pfds[4]) == -1)
{
dev->aio->errnum = qse_aio_syserrtoerrnum(errno);
goto oops;
}
if (minidx == -1) minidx = 4;
maxidx = 5;
}
if (maxidx == -1)
{
dev->aio->errnum = QSE_AIO_EINVAL;
goto oops;
}
if (make_param (rdev->aio, info->cmd, info->flags, &param) <= -1) goto oops;
/* TODO: more advanced fork and exec .. */
pid = standard_fork_and_exec (rdev->aio, pfds, info->flags, &param);
if (pid <= -1)
{
free_param (rdev->aio, &param);
goto oops;
}
free_param (rdev->aio, &param);
rdev->child_pid = pid;
/* this is the parent process */
if (info->flags & QSE_AIO_DEV_PRO_WRITEIN)
{
/*
* 012345
* rw----
* X
* WRITE => 1
*/
close (pfds[0]);
pfds[0] = QSE_AIO_SYSHND_INVALID;
if (qse_aio_makesyshndasync (dev->aio, pfds[1]) <= -1) goto oops;
}
if (info->flags & QSE_AIO_DEV_PRO_READOUT)
{
/*
* 012345
* --rw--
* X
* READ => 2
*/
close (pfds[3]);
pfds[3] = QSE_AIO_SYSHND_INVALID;
if (qse_aio_makesyshndasync (dev->aio, pfds[2]) <= -1) goto oops;
}
if (info->flags & QSE_AIO_DEV_PRO_READERR)
{
/*
* 012345
* ----rw
* X
* READ => 4
*/
close (pfds[5]);
pfds[5] = QSE_AIO_SYSHND_INVALID;
if (qse_aio_makesyshndasync (dev->aio, pfds[4]) <= -1) goto oops;
}
if (pfds[1] != QSE_AIO_SYSHND_INVALID)
{
/* hand over pfds[2] to the first slave device */
slave_info_t si;
si.mi = info;
si.pfd = pfds[1];
si.dev_capa = QSE_AIO_DEV_CAPA_OUT | QSE_AIO_DEV_CAPA_OUT_QUEUED | QSE_AIO_DEV_CAPA_STREAM;
si.id = QSE_AIO_DEV_PRO_IN;
rdev->slave[QSE_AIO_DEV_PRO_IN] = make_slave (dev->aio, &si);
if (!rdev->slave[QSE_AIO_DEV_PRO_IN]) goto oops;
pfds[1] = QSE_AIO_SYSHND_INVALID;
rdev->slave_count++;
}
if (pfds[2] != QSE_AIO_SYSHND_INVALID)
{
/* hand over pfds[2] to the first slave device */
slave_info_t si;
si.mi = info;
si.pfd = pfds[2];
si.dev_capa = QSE_AIO_DEV_CAPA_IN | QSE_AIO_DEV_CAPA_STREAM;
si.id = QSE_AIO_DEV_PRO_OUT;
rdev->slave[QSE_AIO_DEV_PRO_OUT] = make_slave (dev->aio, &si);
if (!rdev->slave[QSE_AIO_DEV_PRO_OUT]) goto oops;
pfds[2] = QSE_AIO_SYSHND_INVALID;
rdev->slave_count++;
}
if (pfds[4] != QSE_AIO_SYSHND_INVALID)
{
/* hand over pfds[4] to the second slave device */
slave_info_t si;
si.mi = info;
si.pfd = pfds[4];
si.dev_capa = QSE_AIO_DEV_CAPA_IN | QSE_AIO_DEV_CAPA_STREAM;
si.id = QSE_AIO_DEV_PRO_ERR;
rdev->slave[QSE_AIO_DEV_PRO_ERR] = make_slave (dev->aio, &si);
if (!rdev->slave[QSE_AIO_DEV_PRO_ERR]) goto oops;
pfds[4] = QSE_AIO_SYSHND_INVALID;
rdev->slave_count++;
}
for (i = 0; i < QSE_COUNTOF(rdev->slave); i++)
{
if (rdev->slave[i]) rdev->slave[i]->master = rdev;
}
rdev->dev_capa = QSE_AIO_DEV_CAPA_VIRTUAL; /* the master device doesn't perform I/O */
rdev->flags = info->flags;
rdev->on_read = info->on_read;
rdev->on_write = info->on_write;
rdev->on_close = info->on_close;
return 0;
oops:
for (i = minidx; i < maxidx; i++)
{
if (pfds[i] != QSE_AIO_SYSHND_INVALID) close (pfds[i]);
}
if (rdev->mcmd)
{
QSE_MMGR_FREE (rdev->aio->mmgr, rdev->mcmd);
free_param (rdev->aio, &param);
}
for (i = QSE_COUNTOF(rdev->slave); i > 0; )
{
i--;
if (rdev->slave[i])
{
qse_aio_killdev (rdev->aio, (qse_aio_dev_t*)rdev->slave[i]);
rdev->slave[i] = QSE_NULL;
}
}
rdev->slave_count = 0;
return -1;
}
static int dev_pro_make_slave (qse_aio_dev_t* dev, void* ctx)
{
qse_aio_dev_pro_slave_t* rdev = (qse_aio_dev_pro_slave_t*)dev;
slave_info_t* si = (slave_info_t*)ctx;
rdev->dev_capa = si->dev_capa;
rdev->id = si->id;
rdev->pfd = si->pfd;
/* keep rdev->master to QSE_NULL. it's set to the right master
* device in dev_pro_make() */
return 0;
}
static int dev_pro_kill_master (qse_aio_dev_t* dev, int force)
{
qse_aio_dev_pro_t* rdev = (qse_aio_dev_pro_t*)dev;
int i, status;
pid_t wpid;
if (rdev->slave_count > 0)
{
for (i = 0; i < QSE_COUNTOF(rdev->slave); i++)
{
if (rdev->slave[i])
{
qse_aio_dev_pro_slave_t* sdev = rdev->slave[i];
/* nullify the pointer to the slave device
* before calling qse_aio_killdev() on the slave device.
* the slave device can check this pointer to tell from
* self-initiated termination or master-driven termination */
rdev->slave[i] = QSE_NULL;
qse_aio_killdev (rdev->aio, (qse_aio_dev_t*)sdev);
}
}
}
if (rdev->child_pid >= 0)
{
if (!(rdev->flags & QSE_AIO_DEV_PRO_FORGET_CHILD))
{
int killed = 0;
await_child:
wpid = waitpid (rdev->child_pid, &status, WNOHANG);
if (wpid == 0)
{
if (force && !killed)
{
if (!(rdev->flags & QSE_AIO_DEV_PRO_FORGET_DIEHARD_CHILD))
{
kill (rdev->child_pid, SIGKILL);
killed = 1;
goto await_child;
}
}
else
{
/* child process is still alive */
rdev->aio->errnum = QSE_AIO_EAGAIN;
return -1; /* call me again */
}
}
/* wpid == rdev->child_pid => full success
* wpid == -1 && errno == ECHILD => no such process. it's waitpid()'ed by some other part of the program?
* other cases ==> can't really handle properly. forget it by returning success
* no need not worry about EINTR because errno can't have the value when WNOHANG is set.
*/
}
printf (">>>>>>>>>>>>>>>>>>> REAPED CHILD %d\n", (int)rdev->child_pid);
rdev->child_pid = -1;
}
if (rdev->on_close) rdev->on_close (rdev, QSE_AIO_DEV_PRO_MASTER);
return 0;
}
static int dev_pro_kill_slave (qse_aio_dev_t* dev, int force)
{
qse_aio_dev_pro_slave_t* rdev = (qse_aio_dev_pro_slave_t*)dev;
if (rdev->master)
{
qse_aio_dev_pro_t* master;
master = rdev->master;
rdev->master = QSE_NULL;
/* indicate EOF */
if (master->on_close) master->on_close (master, rdev->id);
QSE_ASSERT (master->slave_count > 0);
master->slave_count--;
if (master->slave[rdev->id])
{
/* this call is started by the slave device itself.
* if this is the last slave, kill the master also */
if (master->slave_count <= 0)
{
qse_aio_killdev (rdev->aio, (qse_aio_dev_t*)master);
/* the master pointer is not valid from this point onwards
* as the actual master device object is freed in qse_aio_killdev() */
}
}
else
{
/* this call is initiated by this slave device itself.
* if it were by the master device, it would be QSE_NULL as
* nullified by the dev_pro_kill() */
master->slave[rdev->id] = QSE_NULL;
}
}
if (rdev->pfd != QSE_AIO_SYSHND_INVALID)
{
close (rdev->pfd);
rdev->pfd = QSE_AIO_SYSHND_INVALID;
}
return 0;
}
static int dev_pro_read_slave (qse_aio_dev_t* dev, void* buf, qse_aio_iolen_t* len, qse_aio_devaddr_t* srcaddr)
{
qse_aio_dev_pro_slave_t* pro = (qse_aio_dev_pro_slave_t*)dev;
ssize_t x;
x = read (pro->pfd, buf, *len);
if (x <= -1)
{
if (errno == EINPROGRESS || errno == EWOULDBLOCK || errno == EAGAIN) return 0; /* no data available */
if (errno == EINTR) return 0;
pro->aio->errnum = qse_aio_syserrtoerrnum(errno);
return -1;
}
*len = x;
return 1;
}
static int dev_pro_write_slave (qse_aio_dev_t* dev, const void* data, qse_aio_iolen_t* len, const qse_aio_devaddr_t* dstaddr)
{
qse_aio_dev_pro_slave_t* pro = (qse_aio_dev_pro_slave_t*)dev;
ssize_t x;
x = write (pro->pfd, data, *len);
if (x <= -1)
{
if (errno == EINPROGRESS || errno == EWOULDBLOCK || errno == EAGAIN) return 0; /* no data can be written */
if (errno == EINTR) return 0;
pro->aio->errnum = qse_aio_syserrtoerrnum(errno);
return -1;
}
*len = x;
return 1;
}
static qse_aio_syshnd_t dev_pro_getsyshnd (qse_aio_dev_t* dev)
{
return QSE_AIO_SYSHND_INVALID;
}
static qse_aio_syshnd_t dev_pro_getsyshnd_slave (qse_aio_dev_t* dev)
{
qse_aio_dev_pro_slave_t* pro = (qse_aio_dev_pro_slave_t*)dev;
return (qse_aio_syshnd_t)pro->pfd;
}
static int dev_pro_ioctl (qse_aio_dev_t* dev, int cmd, void* arg)
{
qse_aio_dev_pro_t* rdev = (qse_aio_dev_pro_t*)dev;
switch (cmd)
{
case QSE_AIO_DEV_PRO_CLOSE:
{
qse_aio_dev_pro_sid_t sid = *(qse_aio_dev_pro_sid_t*)arg;
if (sid < QSE_AIO_DEV_PRO_IN || sid > QSE_AIO_DEV_PRO_ERR)
{
rdev->aio->errnum = QSE_AIO_EINVAL;
return -1;
}
if (rdev->slave[sid])
{
/* unlike dev_pro_kill_master(), i don't nullify rdev->slave[sid].
* so i treat the closing ioctl as if it's a kill request
* initiated by the slave device itself. */
qse_aio_killdev (rdev->aio, (qse_aio_dev_t*)rdev->slave[sid]);
}
return 0;
}
case QSE_AIO_DEV_PRO_KILL_CHILD:
if (rdev->child_pid >= 0)
{
if (kill (rdev->child_pid, SIGKILL) == -1)
{
rdev->aio->errnum = qse_aio_syserrtoerrnum(errno);
return -1;
}
}
return 0;
default:
dev->aio->errnum = QSE_AIO_EINVAL;
return -1;
}
}
static qse_aio_dev_mth_t dev_pro_methods =
{
dev_pro_make_master,
dev_pro_kill_master,
dev_pro_getsyshnd,
QSE_NULL,
QSE_NULL,
dev_pro_ioctl
};
static qse_aio_dev_mth_t dev_pro_methods_slave =
{
dev_pro_make_slave,
dev_pro_kill_slave,
dev_pro_getsyshnd_slave,
dev_pro_read_slave,
dev_pro_write_slave,
dev_pro_ioctl
};
/* ========================================================================= */
static int pro_ready (qse_aio_dev_t* dev, int events)
{
/* virtual device. no I/O */
dev->aio->errnum = QSE_AIO_EINTERN;
return -1;
}
static int pro_on_read (qse_aio_dev_t* dev, const void* data, qse_aio_iolen_t len, const qse_aio_devaddr_t* srcaddr)
{
/* virtual device. no I/O */
dev->aio->errnum = QSE_AIO_EINTERN;
return -1;
}
static int pro_on_write (qse_aio_dev_t* dev, qse_aio_iolen_t wrlen, void* wrctx, const qse_aio_devaddr_t* dstaddr)
{
/* virtual device. no I/O */
dev->aio->errnum = QSE_AIO_EINTERN;
return -1;
}
static qse_aio_dev_evcb_t dev_pro_event_callbacks =
{
pro_ready,
pro_on_read,
pro_on_write
};
/* ========================================================================= */
static int pro_ready_slave (qse_aio_dev_t* dev, int events)
{
qse_aio_dev_pro_t* pro = (qse_aio_dev_pro_t*)dev;
if (events & QSE_AIO_DEV_EVENT_ERR)
{
pro->aio->errnum = QSE_AIO_EDEVERR;
return -1;
}
if (events & QSE_AIO_DEV_EVENT_HUP)
{
if (events & (QSE_AIO_DEV_EVENT_PRI | QSE_AIO_DEV_EVENT_IN | QSE_AIO_DEV_EVENT_OUT))
{
/* probably half-open? */
return 1;
}
pro->aio->errnum = QSE_AIO_EDEVHUP;
return -1;
}
return 1; /* the device is ok. carry on reading or writing */
}
static int pro_on_read_slave_out (qse_aio_dev_t* dev, const void* data, qse_aio_iolen_t len, const qse_aio_devaddr_t* srcaddr)
{
qse_aio_dev_pro_slave_t* pro = (qse_aio_dev_pro_slave_t*)dev;
return pro->master->on_read (pro->master, data, len, QSE_AIO_DEV_PRO_OUT);
}
static int pro_on_read_slave_err (qse_aio_dev_t* dev, const void* data, qse_aio_iolen_t len, const qse_aio_devaddr_t* srcaddr)
{
qse_aio_dev_pro_slave_t* pro = (qse_aio_dev_pro_slave_t*)dev;
return pro->master->on_read (pro->master, data, len, QSE_AIO_DEV_PRO_ERR);
}
static int pro_on_write_slave (qse_aio_dev_t* dev, qse_aio_iolen_t wrlen, void* wrctx, const qse_aio_devaddr_t* dstaddr)
{
qse_aio_dev_pro_slave_t* pro = (qse_aio_dev_pro_slave_t*)dev;
return pro->master->on_write (pro->master, wrlen, wrctx);
}
static qse_aio_dev_evcb_t dev_pro_event_callbacks_slave_in =
{
pro_ready_slave,
QSE_NULL,
pro_on_write_slave
};
static qse_aio_dev_evcb_t dev_pro_event_callbacks_slave_out =
{
pro_ready_slave,
pro_on_read_slave_out,
QSE_NULL
};
static qse_aio_dev_evcb_t dev_pro_event_callbacks_slave_err =
{
pro_ready_slave,
pro_on_read_slave_err,
QSE_NULL
};
/* ========================================================================= */
static qse_aio_dev_pro_slave_t* make_slave (qse_aio_t* aio, slave_info_t* si)
{
switch (si->id)
{
case QSE_AIO_DEV_PRO_IN:
return (qse_aio_dev_pro_slave_t*)qse_aio_makedev (
aio, QSE_SIZEOF(qse_aio_dev_pro_t),
&dev_pro_methods_slave, &dev_pro_event_callbacks_slave_in, si);
case QSE_AIO_DEV_PRO_OUT:
return (qse_aio_dev_pro_slave_t*)qse_aio_makedev (
aio, QSE_SIZEOF(qse_aio_dev_pro_t),
&dev_pro_methods_slave, &dev_pro_event_callbacks_slave_out, si);
case QSE_AIO_DEV_PRO_ERR:
return (qse_aio_dev_pro_slave_t*)qse_aio_makedev (
aio, QSE_SIZEOF(qse_aio_dev_pro_t),
&dev_pro_methods_slave, &dev_pro_event_callbacks_slave_err, si);
default:
aio->errnum = QSE_AIO_EINVAL;
return QSE_NULL;
}
}
qse_aio_dev_pro_t* qse_aio_dev_pro_make (qse_aio_t* aio, qse_size_t xtnsize, const qse_aio_dev_pro_make_t* info)
{
return (qse_aio_dev_pro_t*)qse_aio_makedev (
aio, QSE_SIZEOF(qse_aio_dev_pro_t) + xtnsize,
&dev_pro_methods, &dev_pro_event_callbacks, (void*)info);
}
void qse_aio_dev_pro_kill (qse_aio_dev_pro_t* dev)
{
qse_aio_killdev (dev->aio, (qse_aio_dev_t*)dev);
}
int qse_aio_dev_pro_write (qse_aio_dev_pro_t* dev, const void* data, qse_aio_iolen_t dlen, void* wrctx)
{
if (dev->slave[0])
{
return qse_aio_dev_write ((qse_aio_dev_t*)dev->slave[0], data, dlen, wrctx, QSE_NULL);
}
else
{
dev->aio->errnum = QSE_AIO_ENOCAPA; /* TODO: is it the right error number? */
return -1;
}
}
int qse_aio_dev_pro_timedwrite (qse_aio_dev_pro_t* dev, const void* data, qse_aio_iolen_t dlen, const qse_ntime_t* tmout, void* wrctx)
{
if (dev->slave[0])
{
return qse_aio_dev_timedwrite ((qse_aio_dev_t*)dev->slave[0], data, dlen, tmout, wrctx, QSE_NULL);
}
else
{
dev->aio->errnum = QSE_AIO_ENOCAPA; /* TODO: is it the right error number? */
return -1;
}
}
int qse_aio_dev_pro_close (qse_aio_dev_pro_t* dev, qse_aio_dev_pro_sid_t sid)
{
return qse_aio_dev_ioctl ((qse_aio_dev_t*)dev, QSE_AIO_DEV_PRO_CLOSE, &sid);
}
int qse_aio_dev_pro_killchild (qse_aio_dev_pro_t* dev)
{
return qse_aio_dev_ioctl ((qse_aio_dev_t*)dev, QSE_AIO_DEV_PRO_KILL_CHILD, QSE_NULL);
}
#if 0
qse_aio_dev_pro_t* qse_aio_dev_pro_getdev (qse_aio_dev_pro_t* pro, qse_aio_dev_pro_sid_t sid)
{
switch (type)
{
case QSE_AIO_DEV_PRO_IN:
return XXX;
case QSE_AIO_DEV_PRO_OUT:
return XXX;
case QSE_AIO_DEV_PRO_ERR:
return XXX;
}
pro->dev->aio = QSE_AIO_EINVAL;
return QSE_NULL;
}
#endif

115
qse/lib/si/aio-prv.h Normal file
View File

@ -0,0 +1,115 @@
/*
* $Id$
*
Copyright (c) 2006-2016 Chung, Hyung-Hwan. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WAfRRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _QSE_LIB_IO_AIO_PRV_H_
#define _QSE_LIB_IO_AIO_PRV_H_
#include <qse/io/aio.h>
#include "../cmn/mem.h"
typedef struct qse_aio_mux_t qse_aio_mux_t;
struct qse_aio_t
{
qse_mmgr_t* mmgr;
qse_aio_errnum_t errnum;
qse_aio_stopreq_t stopreq; /* stop request to abort qse_aio_loop() */
struct
{
qse_aio_dev_t* head;
qse_aio_dev_t* tail;
} actdev; /* active devices */
struct
{
qse_aio_dev_t* head;
qse_aio_dev_t* tail;
} hltdev; /* halted devices */
struct
{
qse_aio_dev_t* head;
qse_aio_dev_t* tail;
} zmbdev; /* zombie devices */
qse_uint8_t bigbuf[65535]; /* TODO: make this dynamic depending on devices added. device may indicate a buffer size required??? */
unsigned int renew_watch: 1;
unsigned int in_exec: 1;
struct
{
qse_size_t capa;
qse_size_t size;
qse_aio_tmrjob_t* jobs;
} tmr;
/* platform specific fields below */
#if defined(_WIN32)
HANDLE iocp;
#else
qse_aio_mux_t* mux;
#endif
};
#ifdef __cplusplus
extern "C" {
#endif
int qse_aio_makesyshndasync (
qse_aio_t* aio,
qse_aio_syshnd_t hnd
);
qse_aio_errnum_t qse_aio_syserrtoerrnum (
int no
);
void qse_aio_cleartmrjobs (
qse_aio_t* aio
);
void qse_aio_firetmrjobs (
qse_aio_t* aio,
const qse_ntime_t* tmbase,
qse_size_t* firecnt
);
int qse_aio_gettmrtmout (
qse_aio_t* aio,
const qse_ntime_t* tmbase,
qse_ntime_t* tmout
);
#ifdef __cplusplus
}
#endif
#endif

1704
qse/lib/si/aio-sck.c Normal file

File diff suppressed because it is too large Load Diff

234
qse/lib/si/aio-tmr.c Normal file
View File

@ -0,0 +1,234 @@
/*
* $Id$
*
Copyright (c) 2006-2016 Chung, Hyung-Hwan. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WAfRRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "aio-prv.h"
#define HEAP_PARENT(x) (((x) - 1) / 2)
#define HEAP_LEFT(x) ((x) * 2 + 1)
#define HEAP_RIGHT(x) ((x) * 2 + 2)
#define YOUNGER_THAN(x,y) (qse_cmptime(&(x)->when, &(y)->when) < 0)
void qse_aio_cleartmrjobs (qse_aio_t* aio)
{
while (aio->tmr.size > 0) qse_aio_deltmrjob (aio, 0);
}
static qse_aio_tmridx_t sift_up (qse_aio_t* aio, qse_aio_tmridx_t index, int notify)
{
qse_aio_tmridx_t parent;
parent = HEAP_PARENT(index);
if (index > 0 && YOUNGER_THAN(&aio->tmr.jobs[index], &aio->tmr.jobs[parent]))
{
qse_aio_tmrjob_t item;
item = aio->tmr.jobs[index];
do
{
/* move down the parent to my current position */
aio->tmr.jobs[index] = aio->tmr.jobs[parent];
if (aio->tmr.jobs[index].idxptr) *aio->tmr.jobs[index].idxptr = index;
/* traverse up */
index = parent;
parent = HEAP_PARENT(parent);
}
while (index > 0 && YOUNGER_THAN(&item, &aio->tmr.jobs[parent]));
aio->tmr.jobs[index] = item;
if (aio->tmr.jobs[index].idxptr) *aio->tmr.jobs[index].idxptr = index;
}
return index;
}
static qse_aio_tmridx_t sift_down (qse_aio_t* aio, qse_aio_tmridx_t index, int notify)
{
qse_size_t base = aio->tmr.size / 2;
if (index < base) /* at least 1 child is under the 'index' position */
{
qse_aio_tmrjob_t item;
item = aio->tmr.jobs[index];
do
{
qse_aio_tmridx_t left, right, younger;
left = HEAP_LEFT(index);
right = HEAP_RIGHT(index);
if (right < aio->tmr.size && YOUNGER_THAN(&aio->tmr.jobs[right], &aio->tmr.jobs[left]))
{
younger = right;
}
else
{
younger = left;
}
if (YOUNGER_THAN(&item, &aio->tmr.jobs[younger])) break;
aio->tmr.jobs[index] = aio->tmr.jobs[younger];
if (aio->tmr.jobs[index].idxptr) *aio->tmr.jobs[index].idxptr = index;
index = younger;
}
while (index < base);
aio->tmr.jobs[index] = item;
if (aio->tmr.jobs[index].idxptr) *aio->tmr.jobs[index].idxptr = index;
}
return index;
}
void qse_aio_deltmrjob (qse_aio_t* aio, qse_aio_tmridx_t index)
{
qse_aio_tmrjob_t item;
QSE_ASSERT (index < aio->tmr.size);
item = aio->tmr.jobs[index];
if (aio->tmr.jobs[index].idxptr) *aio->tmr.jobs[index].idxptr = QSE_AIO_TMRIDX_INVALID;
aio->tmr.size = aio->tmr.size - 1;
if (aio->tmr.size > 0 && index != aio->tmr.size)
{
aio->tmr.jobs[index] = aio->tmr.jobs[aio->tmr.size];
if (aio->tmr.jobs[index].idxptr) *aio->tmr.jobs[index].idxptr = index;
YOUNGER_THAN(&aio->tmr.jobs[index], &item)? sift_up(aio, index, 1): sift_down(aio, index, 1);
}
}
qse_aio_tmridx_t qse_aio_instmrjob (qse_aio_t* aio, const qse_aio_tmrjob_t* job)
{
qse_aio_tmridx_t index = aio->tmr.size;
if (index >= aio->tmr.capa)
{
qse_aio_tmrjob_t* tmp;
qse_size_t new_capa;
QSE_ASSERT (aio->tmr.capa >= 1);
new_capa = aio->tmr.capa * 2;
tmp = (qse_aio_tmrjob_t*)QSE_MMGR_REALLOC (aio->mmgr, aio->tmr.jobs, new_capa * QSE_SIZEOF(*tmp));
if (tmp == QSE_NULL)
{
aio->errnum = QSE_AIO_ENOMEM;
return QSE_AIO_TMRIDX_INVALID;
}
aio->tmr.jobs = tmp;
aio->tmr.capa = new_capa;
}
aio->tmr.size = aio->tmr.size + 1;
aio->tmr.jobs[index] = *job;
if (aio->tmr.jobs[index].idxptr) *aio->tmr.jobs[index].idxptr = index;
return sift_up (aio, index, 0);
}
qse_aio_tmridx_t qse_aio_updtmrjob (qse_aio_t* aio, qse_aio_tmridx_t index, const qse_aio_tmrjob_t* job)
{
qse_aio_tmrjob_t item;
item = aio->tmr.jobs[index];
aio->tmr.jobs[index] = *job;
if (aio->tmr.jobs[index].idxptr) *aio->tmr.jobs[index].idxptr = index;
return YOUNGER_THAN(job, &item)? sift_up (aio, index, 0): sift_down (aio, index, 0);
}
void qse_aio_firetmrjobs (qse_aio_t* aio, const qse_ntime_t* tm, qse_size_t* firecnt)
{
qse_ntime_t now;
qse_aio_tmrjob_t tmrjob;
qse_size_t count = 0;
/* if the current time is not specified, get it from the system */
if (tm) now = *tm;
else qse_gettime (&now);
while (aio->tmr.size > 0)
{
if (qse_cmptime(&aio->tmr.jobs[0].when, &now) > 0) break;
tmrjob = aio->tmr.jobs[0]; /* copy the scheduled job */
qse_aio_deltmrjob (aio, 0); /* deschedule the job */
count++;
tmrjob.handler (aio, &now, &tmrjob); /* then fire the job */
}
if (firecnt) *firecnt = count;
}
int qse_aio_gettmrtmout (qse_aio_t* aio, const qse_ntime_t* tm, qse_ntime_t* tmout)
{
qse_ntime_t now;
/* time-out can't be calculated when there's no job scheduled */
if (aio->tmr.size <= 0)
{
aio->errnum = QSE_AIO_ENOENT;
return -1;
}
/* if the current time is not specified, get it from the system */
if (tm) now = *tm;
else qse_gettime (&now);
qse_subtime (&aio->tmr.jobs[0].when, &now, tmout);
if (tmout->sec < 0) qse_cleartime (tmout);
return 0;
}
qse_aio_tmrjob_t* qse_aio_gettmrjob (qse_aio_t* aio, qse_aio_tmridx_t index)
{
if (index < 0 || index >= aio->tmr.size)
{
aio->errnum = QSE_AIO_ENOENT;
return QSE_NULL;
}
return &aio->tmr.jobs[index];
}
int qse_aio_gettmrjobdeadline (qse_aio_t* aio, qse_aio_tmridx_t index, qse_ntime_t* deadline)
{
if (index < 0 || index >= aio->tmr.size)
{
aio->errnum = QSE_AIO_ENOENT;
return -1;
}
*deadline = aio->tmr.jobs[index].when;
return 0;
}

1468
qse/lib/si/aio.c Normal file

File diff suppressed because it is too large Load Diff

381
qse/lib/si/cnd.c Normal file
View File

@ -0,0 +1,381 @@
/*
* $Id$
*
Copyright (c) 2006-2014 Chung, Hyung-Hwan. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following cnditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of cnditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of cnditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <qse/si/cnd.h>
#include "../cmn/mem.h"
#if (!defined(__unix__) && !defined(__unix)) || defined(HAVE_PTHREAD)
#if defined(_WIN32)
# include <windows.h>
# include <process.h>
#elif defined(__OS2__)
# define INCL_DOSSEMAPHORES
# define INCL_DOSERRORS
# include <os2.h>
#elif defined(__DOS__)
/* implement this */
#else
# if defined(AIX) && defined(__GNUC__)
typedef int crid_t;
typedef unsigned int class_id_t;
# endif
# include <pthread.h>
#endif
qse_cnd_t* qse_cnd_open (qse_mmgr_t* mmgr, qse_size_t xtnsize)
{
qse_cnd_t* cnd;
cnd = (qse_cnd_t*) QSE_MMGR_ALLOC (mmgr, QSE_SIZEOF(qse_cnd_t) + xtnsize);
if (cnd)
{
if (qse_cnd_init (cnd, mmgr) <= -1)
{
QSE_MMGR_FREE (mmgr, cnd);
return QSE_NULL;
}
else QSE_MEMSET (QSE_XTN(cnd), 0, xtnsize);
}
return cnd;
}
void qse_cnd_close (qse_cnd_t* cnd)
{
qse_cnd_fini (cnd);
QSE_MMGR_FREE (cnd->mmgr, cnd);
}
int qse_cnd_init (qse_cnd_t* cnd, qse_mmgr_t* mmgr)
{
QSE_MEMSET (cnd, 0, QSE_SIZEOF(*cnd));
cnd->mmgr = mmgr;
#if defined(_WIN32)
cnd->gone = 0;
cnd->blocked = 0;
cnd->waiting = 0;
cnd->gate = CreateSemaphore (0, 1, 1, 0);
cnd->queue = CreateSemaphore (0, 0, QSE_TYPE_MAX(long), 0);
cnd->mutex = CreateMutex (0, 0, 0);
if (cnd->gate == QSE_NULL ||
cnd->queue == QSE_NULL ||
cnd->mutex == QSE_NULL)
{
if (cnd->gate) CloseHandle (cnd->gate);
if (cnd->queue) CloseHandle (cnd->queue);
if (cnd->mutex) CloseHandle (cnd->mutex);
return -1;
}
#elif defined(__OS2__)
{
APIRET rc;
HEV hev;
rc = DosCreateEventSem (QSE_NULL, &hev, DC_SEM_SHARED, FALSE);
if (rc != NO_ERROR) return -1;
cnd->hnd = hev;
cnd->wait_count = 0;
}
#elif defined(__DOS__)
# error not implemented
#else
if (pthread_cond_init ((pthread_cond_t*)&cnd->hnd, QSE_NULL) != 0) return -1;
#endif
return 0;
}
void qse_cnd_fini (qse_cnd_t* cnd)
{
#if defined(_WIN32)
CloseHandle (cnd->gate);
CloseHandle (cnd->queue);
CloseHandle (cnd->mutex);
#elif defined(__OS2__)
DosCloseEventSem (cnd->hnd);
#elif defined(__DOS__)
# error not implemented
#else
pthread_cond_destroy ((pthread_cond_t*)&cnd->hnd);
#endif
}
void qse_cnd_signal (qse_cnd_t* cnd)
{
#if defined(_WIN32)
unsigned int signals = 0;
WaitForSingleObject ((HANDLE)cnd->mutex, INFINITE);
if (cnd->waiting != 0)
{
if (cnd->blocked == 0)
{
ReleaseMutex ((HANDLE)cnd->mutex);
return;
}
++cnd->waiting;
--cnd->blocked;
signals = 1;
}
else
{
WaitForSingleObject ((HANDLE)cnd->gate, INFINITE);
if (cnd->blocked > cnd->gone)
{
if (cnd->gone != 0)
{
cnd->blocked -= cnd->gone;
cnd->gone = 0;
}
signals = cnd->waiting = 1;
--cnd->blocked;
}
else
{
ReleaseSemaphore ((HANDLE)cnd->gate, 1, QSE_NULL);
}
}
ReleaseMutex ((HANDLE)cnd->mutex);
if (signals) ReleaseSemaphore ((HANDLE)cnd->queue, signals, QSE_NULL);
#elif defined(__OS2__)
if (cnd->wait_count > 0)
{
DosPostEventSem (cnd->hnd);
cnd->wait_count--;
}
#elif defined(__DOS__)
# error not implemented
#elif defined(__BEOS__)
# error not implemented
#else
pthread_cond_signal ((pthread_cond_t*)&cnd->hnd);
#endif
}
void qse_cnd_broadcast (qse_cnd_t* cnd)
{
#if defined(_WIN32)
unsigned int signals = 0;
WaitForSingleObject ((HANDLE)cnd->mutex, INFINITE);
if (cnd->waiting != 0)
{
if (cnd->blocked == 0)
{
ReleaseMutex ((HANDLE)cnd->mutex);
return;
}
cnd->waiting += (signals = cnd->blocked);
cnd->blocked = 0;
}
else
{
WaitForSingleObject ((HANDLE)cnd->gate, INFINITE);
if (cnd->blocked > cnd->gone)
{
if (cnd->gone != 0)
{
cnd->blocked -= cnd->gone;
cnd->gone = 0;
}
signals = cnd->waiting = cnd->blocked;
cnd->blocked = 0;
}
else
{
ReleaseSemaphore ((HANDLE)cnd->gate, 1, QSE_NULL);
}
}
ReleaseMutex ((HANDLE)cnd->mutex);
if (signals) ReleaseSemaphore ((HANDLE)cnd->queue, signals, QSE_NULL);
#elif defined(__OS2__)
while (cnd->wait_count > 0)
{
DosPostEventSem (cnd->hnd);
cnd->wait_count--;
}
#elif defined(__DOS__)
# error not implemented
#elif defined(__BEOS__)
# error not implemented
#else
pthread_cond_broadcast ((pthread_cond_t*)&cnd->hnd);
#endif
}
void qse_cnd_wait (qse_cnd_t* cnd, qse_mtx_t* mutex, const qse_ntime_t* waiting_time)
{
#if defined(_WIN32)
unsigned int was_waiting, was_gone;
int signaled;
WaitForSingleObject ((HANDLE)cnd->gate, INFINITE);
++cnd->blocked;
ReleaseSemaphore ((HANDLE)cnd->gate, 1, QSE_NULL);
qse_mtx_unlock (mutex);
if (waiting_time)
{
DWORD msec;
msec = QSE_SECNSEC_TO_MSEC (waiting_time->sec, waiting_time->nsec);
signaled = (WaitForSingleObject((HANDLE)cnd->queue, msec) == WAIT_OBJECT_0);
}
else
{
WaitForSingleObject ((HANDLE)cnd->queue, INFINITE);
signaled = 1;
}
was_waiting = 0;
was_gone = 0;
WaitForSingleObject ((HANDLE)cnd->mutex, INFINITE);
was_waiting = cnd->waiting;
was_gone = cnd->gone;
if (was_waiting != 0)
{
if (!signaled)
{
/* timed out */
if (cnd->blocked != 0) --cnd->blocked;
else ++cnd->gone;
}
if (--cnd->waiting == 0)
{
if (cnd->blocked != 0)
{
ReleaseSemaphore ((HANDLE)cnd->gate, 1, QSE_NULL);
was_waiting = 0;
}
else if (cnd->gone != 0)
{
cnd->gone = 0;
}
}
}
else if (++cnd->gone == QSE_TYPE_MAX(unsigned int) / 2)
{
WaitForSingleObject ((HANDLE)cnd->gate, INFINITE);
cnd->blocked -= cnd->gone;
ReleaseSemaphore ((HANDLE)cnd->gate, 1, QSE_NULL);
cnd->gone = 0;
}
ReleaseMutex ((HANDLE)cnd->mutex);
if (was_waiting == 1)
{
for (;was_gone; --was_gone)
{
WaitForSingleObject ((HANDLE)cnd->queue, INFINITE);
}
ReleaseSemaphore ((HANDLE)cnd->gate, 1, QSE_NULL);
}
qse_mtx_lock (mutex, QSE_NULL);
#elif defined(__OS2__)
cnd->wait_count++;
qse_mtx_unlock (mutex);
if (waiting_time)
{
ULONG msec;
msec = QSE_SECNSEC_TO_MSEC(waiting_time->sec, waiting_time->nsec);
DosWaitEventSem (cnd->hnd, msec);
}
else
{
DosWaitEventSem (cnd->hnd, SEM_INDEFINITE_WAIT);
}
qse_mtx_lock (mutex, QSE_NULL);
#elif defined(__DOS__)
# error not implemented
#elif defined(__BEOS__)
# error not implemented
#else
if (waiting_time)
{
qse_ntime_t t;
struct timespec ts;
qse_gettime (&t);
qse_addtime (&t, waiting_time, &t);
ts.tv_sec = t.sec;
ts.tv_nsec = t.nsec;
pthread_cond_timedwait ((pthread_cond_t*)&cnd->hnd, (pthread_mutex_t*)&mutex->hnd, &ts);
}
else
{
/* no waiting */
pthread_cond_wait ((pthread_cond_t*)&cnd->hnd, (pthread_mutex_t*)&mutex->hnd);
}
#endif
}
#endif

1668
qse/lib/si/fio.c Normal file

File diff suppressed because it is too large Load Diff

162
qse/lib/si/intr.c Normal file
View File

@ -0,0 +1,162 @@
/*
* $Id$
*
Copyright (c) 2006-2014 Chung, Hyung-Hwan. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <qse/si/intr.h>
#if defined(_WIN32)
# include <windows.h>
#elif defined(__OS2__)
# define INCL_DOSPROCESS
# define INCL_DOSEXCEPTIONS
# define INCL_ERRORS
# include <os2.h>
#elif defined(__DOS__)
# include <dos.h>
# include <signal.h>
#else
# include <unistd.h>
# include <signal.h>
# include <errno.h>
#endif
static qse_intr_handler_t intr_handler = QSE_NULL;
static void* intr_handler_arg = QSE_NULL;
#if defined(_WIN32)
static BOOL WINAPI __intr_handler (DWORD ctrl_type)
{
if (ctrl_type == CTRL_C_EVENT ||
ctrl_type == CTRL_CLOSE_EVENT)
{
if (intr_handler) intr_handler (intr_handler_arg);
return TRUE;
}
return FALSE;
}
#elif defined(__OS2__)
static EXCEPTIONREGISTRATIONRECORD os2_excrr = { 0 };
static ULONG _System __intr_handler (
PEXCEPTIONREPORTRECORD p1,
PEXCEPTIONREGISTRATIONRECORD p2,
PCONTEXTRECORD p3,
PVOID pv)
{
if (p1->ExceptionNum == XCPT_SIGNAL)
{
if (p1->ExceptionInfo[0] == XCPT_SIGNAL_INTR ||
p1->ExceptionInfo[0] == XCPT_SIGNAL_KILLPROC ||
p1->ExceptionInfo[0] == XCPT_SIGNAL_BREAK)
{
APIRET rc;
if (intr_handler) intr_handler (intr_handler_arg);
rc = DosAcknowledgeSignalException (p1->ExceptionInfo[0]);
return (rc != NO_ERROR)? 1: XCPT_CONTINUE_EXECUTION;
}
}
return XCPT_CONTINUE_SEARCH; /* exception not resolved */
}
#elif defined(__DOS__)
static void __intr_handler (void)
{
if (intr_handler) intr_handler (intr_handler_arg);
}
#else
static void __intr_handler (int sig)
{
if (intr_handler) intr_handler (intr_handler_arg);
}
static int setsignal (int sig, void(*handler)(int), int restart)
{
struct sigaction sa_int;
sa_int.sa_handler = handler;
sigemptyset (&sa_int.sa_mask);
sa_int.sa_flags = 0;
if (restart)
{
#if defined(SA_RESTART)
sa_int.sa_flags |= SA_RESTART;
#endif
}
else
{
#if defined(SA_INTERRUPT)
sa_int.sa_flags |= SA_INTERRUPT;
#endif
}
return sigaction (sig, &sa_int, NULL);
}
#endif
void qse_setintrhandler (qse_intr_handler_t handler, void* arg)
{
intr_handler = handler;
intr_handler_arg = arg;
#if defined(_WIN32)
SetConsoleCtrlHandler (__intr_handler, TRUE);
#elif defined(__OS2__)
os2_excrr.ExceptionHandler = (ERR)__intr_handler;
DosSetExceptionHandler (&os2_excrr); /* TODO: check if NO_ERROR is returned */
#elif defined(__DOS__)
signal (SIGINT, __intr_handler);
#else
/*setsignal (SIGINT, __intr_handler, 1); TO BE MORE COMPATIBLE WITH WIN32*/
setsignal (SIGINT, __intr_handler, 0);
#endif
}
void qse_clearintrhandler (void)
{
intr_handler = QSE_NULL;
intr_handler_arg = QSE_NULL;
#if defined(_WIN32)
SetConsoleCtrlHandler (__intr_handler, FALSE);
#elif defined(__OS2__)
DosUnsetExceptionHandler (&os2_excrr);
#elif defined(__DOS__)
signal (SIGINT, SIG_DFL);
#else
setsignal (SIGINT, SIG_DFL, 1);
#endif
}

257
qse/lib/si/mtx.c Normal file
View File

@ -0,0 +1,257 @@
/*
* $Id$
*
Copyright (c) 2006-2014 Chung, Hyung-Hwan. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <qse/si/mtx.h>
#include "../cmn/mem.h"
#if (!defined(__unix__) && !defined(__unix)) || defined(HAVE_PTHREAD)
#if defined(_WIN32)
# include <windows.h>
# include <process.h>
#elif defined(__OS2__)
# define INCL_DOSSEMAPHORES
# define INCL_DOSERRORS
# include <os2.h>
#elif defined(__DOS__)
/* implement this */
#elif defined(__BEOS__)
# include <be/kernel/OS.h>
#else
# if defined(AIX) && defined(__GNUC__)
typedef int crid_t;
typedef unsigned int class_id_t;
# endif
# include <pthread.h>
#endif
qse_mtx_t* qse_mtx_open (qse_mmgr_t* mmgr, qse_size_t xtnsize)
{
qse_mtx_t* mtx;
mtx = (qse_mtx_t*) QSE_MMGR_ALLOC (mmgr, QSE_SIZEOF(qse_mtx_t) + xtnsize);
if (mtx)
{
if (qse_mtx_init (mtx, mmgr) <= -1)
{
QSE_MMGR_FREE (mmgr, mtx);
return QSE_NULL;
}
else QSE_MEMSET (QSE_XTN(mtx), 0, xtnsize);
}
return mtx;
}
void qse_mtx_close (qse_mtx_t* mtx)
{
qse_mtx_fini (mtx);
QSE_MMGR_FREE (mtx->mmgr, mtx);
}
int qse_mtx_init (qse_mtx_t* mtx, qse_mmgr_t* mmgr)
{
QSE_MEMSET (mtx, 0, QSE_SIZEOF(*mtx));
mtx->mmgr = mmgr;
#if defined(_WIN32)
mtx->hnd = CreateMutex (QSE_NULL, FALSE, QSE_NULL);
if (mtx->hnd == QSE_NULL) return -1;
#elif defined(__OS2__)
{
APIRET rc;
HMTX m;
rc = DosCreateMutexSem (QSE_NULL, &m, DC_SEM_SHARED, FALSE);
if (rc != NO_ERROR) return -1;
mtx->hnd = m;
}
#elif defined(__DOS__)
# error not implemented
#elif defined(__BEOS__)
mtx->hnd = create_sem (1, QSE_NULL);
if (mtx->hnd < B_OK) return -1;
#else
/*
qse_ensure (pthread_mutexattr_init (&attr) == 0);
if (pthread_mutexattr_settype (&attr, type) != 0)
{
int num = qse_geterrno();
pthread_mutexattr_destroy (&attr);
if (mtx->__dynamic) qse_free (mtx);
qse_seterrno (num);
return QSE_NULL;
}
qse_ensure (pthread_mutex_init (&mtx->hnd, &attr) == 0);
qse_ensure (pthread_mutexattr_destroy (&attr) == 0);
*/
if (pthread_mutex_init ((pthread_mutex_t*)&mtx->hnd, QSE_NULL) != 0) return -1;
#endif
return 0;
}
void qse_mtx_fini (qse_mtx_t* mtx)
{
#if defined(_WIN32)
CloseHandle (mtx->hnd);
#elif defined(__OS2__)
DosCloseMutexSem (mtx->hnd);
#elif defined(__DOS__)
# error not implemented
#elif defined(__BEOS__)
/*if (delete_sem(mtx->hnd) != B_NO_ERROR) return -1;*/
delete_sem(mtx->hnd);
#else
pthread_mutex_destroy((pthread_mutex_t*)&mtx->hnd);
#endif
}
qse_mmgr_t* qse_mtx_getmmgr (qse_mtx_t* mtx)
{
return mtx->mmgr;
}
void* qse_mtx_getxtn (qse_mtx_t* mtx)
{
return QSE_XTN (mtx);
}
int qse_mtx_lock (qse_mtx_t* mtx, const qse_ntime_t* waiting_time)
{
#if defined(_WIN32)
/*
* MSDN
* WAIT_ABANDONED The specified object is a mutex object that was
* not released by the thread that owned the mutex
* object before the owning thread terminated.
* Ownership of the mutex object is granted to the
* calling thread, and the mutex is set to nonsignaled.
* WAIT_OBJECT_0 The state of the specified object is signaled.
* WAIT_TIMEOUT The time-out interval elapsed, and the object's
* state is nonsignaled.
* WAIT_FAILED An error occurred
*/
if (waiting_time)
{
DWORD msec;
msec = QSE_SECNSEC_TO_MSEC (waiting_time->sec, waiting_time->nsec);
if (WaitForSingleObject(mtx->hnd, msec) != WAIT_OBJECT_0) return -1;
}
else
{
if (WaitForSingleObject (mtx->hnd, INFINITE) == WAIT_FAILED) return -1;
}
#elif defined(__OS2__)
if (waiting_time)
{
ULONG msec;
msec = QSE_SECNSEC_TO_MSEC (waiting_time->sec, waiting_time->nsec);
if (DosRequestMutexSem (mtx->hnd, msec) != NO_ERROR) return -1;
}
else
{
if (DosRequestMutexSem (mtx->hnd, SEM_INDEFINITE_WAIT) != NO_ERROR) return -1;
}
#elif defined(__DOS__)
/* nothing to do */
#elif defined(__BEOS__)
if (waiting_time)
{
/* TODO: check for B_WOULD_BLOCK */
/*if (acquire_sem_etc(mtx->hnd, 1, B_ABSOLUTE_TIMEOUT, 0) != B_NO_ERROR) return -1;*/
bigtime_t usec;
usec = QSE_SECNSEC_TO_USEC (waiting_time->sec, waiting_time->nsec);
if (acquire_sem_etc(mtx->hnd, 1, B_TIMEOUT, 0) != B_NO_ERROR) return -1;
}
else
{
if (acquire_sem(mtx->hnd) != B_NO_ERROR) return -1;
}
#else
if (waiting_time)
{
qse_ntime_t t;
struct timespec ts;
qse_gettime (&t);
qse_addtime (&t, waiting_time, &t);
ts.tv_sec = t.sec;
ts.tv_nsec = t.nsec;
if (pthread_mutex_timedlock ((pthread_mutex_t*)&mtx->hnd, &ts) != 0) return -1;
}
else
{
if (pthread_mutex_lock ((pthread_mutex_t*)&mtx->hnd) != 0) return -1;
}
#endif
return 0;
}
int qse_mtx_unlock (qse_mtx_t* mtx)
{
#if defined(_WIN32)
if (ReleaseMutex (mtx->hnd) == FALSE) return -1;
#elif defined(__OS2__)
if (DosReleaseMutexSem (mtx->hnd) != NO_ERROR) return -1;
#elif defined(__DOS__)
/* nothing to do */
#elif defined(__BEOS__)
if (release_sem(mtx->hnd) != B_NO_ERROR) return -1;
#else
if (pthread_mutex_unlock ((pthread_mutex_t*)&mtx->hnd) != 0) return -1;
#endif
return 0;
}
#endif

1050
qse/lib/si/mux.c Normal file

File diff suppressed because it is too large Load Diff

1608
qse/lib/si/nwio.c Normal file

File diff suppressed because it is too large Load Diff

2519
qse/lib/si/pio.c Normal file

File diff suppressed because it is too large Load Diff

251
qse/lib/si/rwl.c Normal file
View File

@ -0,0 +1,251 @@
/*
* $Id$
*
Copyright (c) 2006-2014 Chung, Hyung-Hwan. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <qse/si/rwl.h>
#include "../cmn/mem.h"
qse_rwl_t* qse_rwl_open (qse_mmgr_t* mmgr, qse_size_t xtnsize, int flags)
{
qse_rwl_t* rwl;
rwl = (qse_rwl_t*) QSE_MMGR_ALLOC (mmgr, QSE_SIZEOF(qse_rwl_t) + xtnsize);
if (rwl)
{
if (qse_rwl_init (rwl, mmgr, flags) <= -1)
{
QSE_MMGR_FREE (mmgr, rwl);
return QSE_NULL;
}
else QSE_MEMSET (QSE_XTN(rwl), 0, xtnsize);
}
return rwl;
}
void qse_rwl_close (qse_rwl_t* rwl)
{
qse_rwl_fini (rwl);
QSE_MMGR_FREE (rwl->mmgr, rwl);
}
int qse_rwl_init (qse_rwl_t* rwl, qse_mmgr_t* mmgr, int flags)
{
QSE_MEMSET (rwl, 0, QSE_SIZEOF(*rwl));
rwl->mmgr = mmgr;
rwl->flags = flags;
if (qse_mtx_init (&rwl->mtx, mmgr) <= -1)
{
return -1;
}
if (qse_cnd_init (&rwl->rcnd, mmgr) <= -1)
{
qse_mtx_fini (&rwl->mtx);
return -1;
}
if (qse_cnd_init (&rwl->wcnd, mmgr) <= -1)
{
qse_cnd_fini (&rwl->rcnd);
qse_mtx_fini (&rwl->mtx);
return -1;
}
rwl->rwait_count = 0;
rwl->wwait_count = 0;
rwl->ractive_count = 0;
rwl->wactive_count = 0;
return 0;
}
void qse_rwl_fini (qse_rwl_t* rwl)
{
qse_cnd_fini (&rwl->wcnd);
qse_cnd_fini (&rwl->rcnd);
qse_mtx_fini (&rwl->mtx);
}
qse_mmgr_t* qse_rwl_getmmgr (qse_rwl_t* rwl)
{
return rwl->mmgr;
}
void* qse_rwl_getxtn (qse_rwl_t* rwl)
{
return QSE_XTN (rwl);
}
int qse_rwl_lockr (qse_rwl_t* rwl, const qse_ntime_t* waiting_time)
{
qse_ntime_t dead_line, now, rem, zero;
if (waiting_time)
{
qse_cleartime (&zero);
qse_gettime (&now);
qse_addtime (&now, waiting_time, &dead_line);
}
if (qse_mtx_lock (&rwl->mtx, waiting_time) <= -1) return -1;
if (rwl->wactive_count > 0 || ((rwl->flags & QSE_RWL_PREFER_WRITER) && rwl->wwait_count > 0))
{
rwl->rwait_count++;
while (rwl->wactive_count > 0 || ((rwl->flags & QSE_RWL_PREFER_WRITER) && rwl->wwait_count > 0))
{
if (waiting_time)
{
qse_gettime (&now);
qse_subtime (&dead_line, &now, &rem);
if (qse_cmptime(&rem, &zero) <= 0)
{
/* timed out */
rwl->rwait_count--;
qse_mtx_unlock (&rwl->mtx);
return -1;
}
qse_cnd_wait (&rwl->rcnd, &rwl->mtx, &rem);
}
else
{
qse_cnd_wait (&rwl->rcnd, &rwl->mtx, QSE_NULL);
}
}
rwl->rwait_count--;
}
rwl->ractive_count++;
qse_mtx_unlock (&rwl->mtx);
return 0;
}
int qse_rwl_unlockr (qse_rwl_t* rwl)
{
if (qse_mtx_lock (&rwl->mtx, QSE_NULL) <= -1) return -1;
if (rwl->ractive_count <= 0)
{
qse_mtx_unlock (&rwl->mtx);
return -1;
}
rwl->ractive_count--;
if (rwl->ractive_count == 0 && rwl->wwait_count > 0)
{
qse_cnd_signal (&rwl->wcnd);
}
qse_mtx_unlock (&rwl->mtx);
return 0;
}
int qse_rwl_lockw (qse_rwl_t* rwl, const qse_ntime_t* waiting_time)
{
qse_ntime_t dead_line, now, rem, zero;
if (waiting_time)
{
qse_cleartime (&zero);
qse_gettime (&now);
qse_addtime (&now, waiting_time, &dead_line);
}
if (qse_mtx_lock (&rwl->mtx, waiting_time) <= -1) return -1;
if (rwl->wactive_count > 0 || rwl->ractive_count > 0)
{
rwl->wwait_count++;
while (rwl->wactive_count > 0 || rwl->ractive_count > 0)
{
if (waiting_time)
{
qse_gettime (&now);
qse_subtime (&dead_line, &now, &rem);
if (qse_cmptime(&rem, &zero) <= 0)
{
/* timed out */
rwl->wwait_count--;
qse_mtx_unlock (&rwl->mtx);
return -1;
}
qse_cnd_wait (&rwl->wcnd, &rwl->mtx, &rem);
}
else
{
qse_cnd_wait (&rwl->wcnd, &rwl->mtx, QSE_NULL);
}
}
rwl->wwait_count--;
}
rwl->wactive_count++;
qse_mtx_unlock (&rwl->mtx);
return 0;
}
int qse_rwl_unlockw (qse_rwl_t* rwl)
{
if (qse_mtx_lock (&rwl->mtx, QSE_NULL) <= -1) return -1;
if (rwl->wactive_count <= 0)
{
qse_mtx_unlock (&rwl->mtx);
return -1;
}
rwl->wactive_count--;
#if 0
if (rwl->flags & QSE_RWL_PREFER_WRITER)
{
if (rwl->wwait_count > 0)
{
qse_cnd_signal (&rwl->wcnd);
}
else if (rwl->rwait_count > 0)
{
qse_cnd_broadcast (&rwl->rcnd);
}
}
else
{
#endif
if (rwl->rwait_count > 0)
{
qse_cnd_broadcast (&rwl->rcnd);
}
/*else*/ if (rwl->wwait_count > 0)
{
qse_cnd_signal (&rwl->wcnd);
}
#if 0
}
#endif
qse_mtx_unlock (&rwl->mtx);
return 0;
}

982
qse/lib/si/sio.c Normal file
View File

@ -0,0 +1,982 @@
/*
* $Id$
*
Copyright (c) 2006-2014 Chung, Hyung-Hwan. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <qse/si/sio.h>
#include <qse/cmn/mbwc.h>
#include "../cmn/mem.h"
#include "../cmn/fmt.h"
#if defined(_WIN32)
# include <windows.h> /* for the UGLY hack */
#elif defined(__OS2__)
/* nothing */
#elif defined(__DOS__)
/* nothing */
#else
# include "../cmn/syscall.h"
#endif
/* internal status codes */
enum
{
STATUS_UTF8_CONSOLE = (1 << 0),
STATUS_LINE_BREAK = (1 << 1)
};
static qse_ssize_t file_input (
qse_tio_t* tio, qse_tio_cmd_t cmd, void* buf, qse_size_t size);
static qse_ssize_t file_output (
qse_tio_t* tio, qse_tio_cmd_t cmd, void* buf, qse_size_t size);
static qse_sio_errnum_t fio_errnum_to_sio_errnum (qse_fio_t* fio)
{
switch (fio->errnum)
{
case QSE_FIO_ENOMEM:
return QSE_SIO_ENOMEM;
case QSE_FIO_EINVAL:
return QSE_SIO_EINVAL;
case QSE_FIO_EACCES:
return QSE_SIO_EACCES;
case QSE_FIO_ENOENT:
return QSE_SIO_ENOENT;
case QSE_FIO_EEXIST:
return QSE_SIO_EEXIST;
case QSE_FIO_EINTR:
return QSE_SIO_EINTR;
case QSE_FIO_EPIPE:
return QSE_SIO_EPIPE;
case QSE_FIO_EAGAIN:
return QSE_SIO_EAGAIN;
case QSE_FIO_ESYSERR:
return QSE_SIO_ESYSERR;
case QSE_FIO_ENOIMPL:
return QSE_SIO_ENOIMPL;
default:
return QSE_SIO_EOTHER;
}
}
static qse_sio_errnum_t tio_errnum_to_sio_errnum (qse_tio_t* tio)
{
switch (tio->errnum)
{
case QSE_TIO_ENOMEM:
return QSE_SIO_ENOMEM;
case QSE_TIO_EINVAL:
return QSE_SIO_EINVAL;
case QSE_TIO_EACCES:
return QSE_SIO_EACCES;
case QSE_TIO_ENOENT:
return QSE_SIO_ENOENT;
case QSE_TIO_EILSEQ:
return QSE_SIO_EILSEQ;
case QSE_TIO_EICSEQ:
return QSE_SIO_EICSEQ;
case QSE_TIO_EILCHR:
return QSE_SIO_EILCHR;
default:
return QSE_SIO_EOTHER;
}
}
qse_sio_t* qse_sio_open (
qse_mmgr_t* mmgr, qse_size_t xtnsize, const qse_char_t* file, int flags)
{
qse_sio_t* sio;
sio = QSE_MMGR_ALLOC (mmgr, QSE_SIZEOF(qse_sio_t) + xtnsize);
if (sio)
{
if (qse_sio_init (sio, mmgr, file, flags) <= -1)
{
QSE_MMGR_FREE (mmgr, sio);
return QSE_NULL;
}
else QSE_MEMSET (QSE_XTN(sio), 0, xtnsize);
}
return sio;
}
qse_sio_t* qse_sio_openstd (
qse_mmgr_t* mmgr, qse_size_t xtnsize, qse_sio_std_t std, int flags)
{
qse_sio_t* sio;
qse_fio_hnd_t hnd;
/* Is this necessary?
if (flags & QSE_SIO_KEEPATH)
{
sio->errnum = QSE_SIO_EINVAL;
return QSE_NULL;
}
*/
if (qse_getstdfiohandle (std, &hnd) <= -1) return QSE_NULL;
sio = qse_sio_open (mmgr, xtnsize,
(const qse_char_t*)&hnd, flags | QSE_SIO_HANDLE | QSE_SIO_NOCLOSE);
#if defined(_WIN32)
if (sio)
{
DWORD mode;
if (GetConsoleMode (sio->file.handle, &mode) == TRUE &&
GetConsoleOutputCP() == CP_UTF8)
{
sio->status |= STATUS_UTF8_CONSOLE;
}
}
#endif
return sio;
}
void qse_sio_close (qse_sio_t* sio)
{
qse_sio_fini (sio);
QSE_MMGR_FREE (sio->mmgr, sio);
}
int qse_sio_init (
qse_sio_t* sio, qse_mmgr_t* mmgr, const qse_char_t* path, int flags)
{
int mode;
int topt = 0;
QSE_MEMSET (sio, 0, QSE_SIZEOF(*sio));
sio->mmgr = mmgr;
mode = QSE_FIO_RUSR | QSE_FIO_WUSR |
QSE_FIO_RGRP | QSE_FIO_ROTH;
/* sio flag enumerators redefines most fio flag enumerators and
* compose a superset of fio flag enumerators. when a user calls
* this function, a user can specify a sio flag enumerator not
* present in the fio flag enumerator. mask off such an enumerator. */
if (qse_fio_init (
&sio->file, mmgr, path,
(flags & ~QSE_FIO_RESERVED), mode) <= -1)
{
sio->errnum = fio_errnum_to_sio_errnum (&sio->file);
goto oops00;
}
if (flags & QSE_SIO_IGNOREMBWCERR) topt |= QSE_TIO_IGNOREMBWCERR;
if (flags & QSE_SIO_NOAUTOFLUSH) topt |= QSE_TIO_NOAUTOFLUSH;
if ((flags & QSE_SIO_KEEPPATH) && !(flags & QSE_SIO_HANDLE))
{
sio->path = qse_strdup (path, sio->mmgr);
if (sio->path == QSE_NULL)
{
sio->errnum = QSE_SIO_ENOMEM;
goto oops01;
}
}
if (qse_tio_init(&sio->tio.io, mmgr, topt) <= -1)
{
sio->errnum = tio_errnum_to_sio_errnum (&sio->tio.io);
goto oops02;
}
/* store the back-reference to sio in the extension area.*/
QSE_ASSERT (QSE_XTN(&sio->tio.io) == &sio->tio.xtn);
*(qse_sio_t**)QSE_XTN(&sio->tio.io) = sio;
if (qse_tio_attachin (&sio->tio.io, file_input, sio->inbuf, QSE_COUNTOF(sio->inbuf)) <= -1 ||
qse_tio_attachout (&sio->tio.io, file_output, sio->outbuf, QSE_COUNTOF(sio->outbuf)) <= -1)
{
if (sio->errnum == QSE_SIO_ENOERR)
sio->errnum = tio_errnum_to_sio_errnum (&sio->tio.io);
goto oops03;
}
#if defined(__OS2__)
if (flags & QSE_SIO_LINEBREAK) sio->status |= STATUS_LINE_BREAK;
#endif
return 0;
oops03:
qse_tio_fini (&sio->tio.io);
oops02:
if (sio->path) QSE_MMGR_FREE (sio->mmgr, sio->path);
oops01:
qse_fio_fini (&sio->file);
oops00:
return -1;
}
int qse_sio_initstd (
qse_sio_t* sio, qse_mmgr_t* mmgr, qse_sio_std_t std, int flags)
{
int n;
qse_fio_hnd_t hnd;
if (qse_getstdfiohandle (std, &hnd) <= -1) return -1;
n = qse_sio_init (sio, mmgr,
(const qse_char_t*)&hnd, flags | QSE_SIO_HANDLE | QSE_SIO_NOCLOSE);
#if defined(_WIN32)
if (n >= 0)
{
DWORD mode;
if (GetConsoleMode (sio->file.handle, &mode) == TRUE &&
GetConsoleOutputCP() == CP_UTF8)
{
sio->status |= STATUS_UTF8_CONSOLE;
}
}
#endif
return n;
}
void qse_sio_fini (qse_sio_t* sio)
{
/*if (qse_sio_flush (sio) <= -1) return -1;*/
qse_sio_flush (sio);
qse_tio_fini (&sio->tio.io);
qse_fio_fini (&sio->file);
if (sio->path) QSE_MMGR_FREE (sio->mmgr, sio->path);
}
qse_mmgr_t* qse_sio_getmmgr (qse_sio_t* sio)
{
return sio->mmgr;
}
void* qse_sio_getxtn (qse_sio_t* sio)
{
return QSE_XTN (sio);
}
qse_sio_errnum_t qse_sio_geterrnum (const qse_sio_t* sio)
{
return sio->errnum;
}
qse_cmgr_t* qse_sio_getcmgr (qse_sio_t* sio)
{
return qse_tio_getcmgr (&sio->tio.io);
}
void qse_sio_setcmgr (qse_sio_t* sio, qse_cmgr_t* cmgr)
{
qse_tio_setcmgr (&sio->tio.io, cmgr);
}
qse_sio_hnd_t qse_sio_gethandle (const qse_sio_t* sio)
{
/*return qse_fio_gethandle (&sio->file);*/
return QSE_FIO_HANDLE(&sio->file);
}
const qse_char_t* qse_sio_getpath (qse_sio_t* sio)
{
/* this path is valid if QSE_SIO_HANDLE is off and QSE_SIO_KEEPPATH is on */
return sio->path;
}
qse_ssize_t qse_sio_flush (qse_sio_t* sio)
{
qse_ssize_t n;
sio->errnum = QSE_SIO_ENOERR;
n = qse_tio_flush (&sio->tio.io);
if (n <= -1 && sio->errnum == QSE_SIO_ENOERR)
sio->errnum = tio_errnum_to_sio_errnum (&sio->tio.io);
return n;
}
void qse_sio_drain (qse_sio_t* sio)
{
qse_tio_drain (&sio->tio.io);
}
qse_ssize_t qse_sio_getmb (qse_sio_t* sio, qse_mchar_t* c)
{
qse_ssize_t n;
sio->errnum = QSE_SIO_ENOERR;
n = qse_tio_readmbs (&sio->tio.io, c, 1);
if (n <= -1 && sio->errnum == QSE_SIO_ENOERR)
sio->errnum = tio_errnum_to_sio_errnum (&sio->tio.io);
return n;
}
qse_ssize_t qse_sio_getwc (qse_sio_t* sio, qse_wchar_t* c)
{
qse_ssize_t n;
sio->errnum = QSE_SIO_ENOERR;
n = qse_tio_readwcs (&sio->tio.io, c, 1);
if (n <= -1 && sio->errnum == QSE_SIO_ENOERR)
sio->errnum = tio_errnum_to_sio_errnum (&sio->tio.io);
return n;
}
qse_ssize_t qse_sio_getmbs (
qse_sio_t* sio, qse_mchar_t* buf, qse_size_t size)
{
qse_ssize_t n;
if (size <= 0) return 0;
#if defined(_WIN32)
/* Using ReadConsoleA() didn't help at all.
* so I don't implement any hack here */
#endif
sio->errnum = QSE_SIO_ENOERR;
n = qse_tio_readmbs (&sio->tio.io, buf, size - 1);
if (n <= -1)
{
if (sio->errnum == QSE_SIO_ENOERR)
sio->errnum = tio_errnum_to_sio_errnum (&sio->tio.io);
return -1;
}
buf[n] = QSE_MT('\0');
return n;
}
qse_ssize_t qse_sio_getmbsn (
qse_sio_t* sio, qse_mchar_t* buf, qse_size_t size)
{
qse_ssize_t n;
#if defined(_WIN32)
/* Using ReadConsoleA() didn't help at all.
* so I don't implement any hack here */
#endif
sio->errnum = QSE_SIO_ENOERR;
n = qse_tio_readmbs (&sio->tio.io, buf, size);
if (n <= -1 && sio->errnum == QSE_SIO_ENOERR)
sio->errnum = tio_errnum_to_sio_errnum (&sio->tio.io);
return n;
}
qse_ssize_t qse_sio_getwcs (
qse_sio_t* sio, qse_wchar_t* buf, qse_size_t size)
{
qse_ssize_t n;
if (size <= 0) return 0;
#if defined(_WIN32)
/* Using ReadConsoleA() didn't help at all.
* so I don't implement any hack here */
#endif
sio->errnum = QSE_SIO_ENOERR;
n = qse_tio_readwcs (&sio->tio.io, buf, size - 1);
if (n <= -1)
{
if (sio->errnum == QSE_SIO_ENOERR)
sio->errnum = tio_errnum_to_sio_errnum (&sio->tio.io);
return -1;
}
buf[n] = QSE_WT('\0');
return n;
}
qse_ssize_t qse_sio_getwcsn (
qse_sio_t* sio, qse_wchar_t* buf, qse_size_t size)
{
qse_ssize_t n;
#if defined(_WIN32)
/* Using ReadConsoleW() didn't help at all.
* so I don't implement any hack here */
#endif
sio->errnum = QSE_SIO_ENOERR;
n = qse_tio_readwcs (&sio->tio.io, buf, size);
if (n <= -1 && sio->errnum == QSE_SIO_ENOERR)
sio->errnum = tio_errnum_to_sio_errnum (&sio->tio.io);
return n;
}
qse_ssize_t qse_sio_putmb (qse_sio_t* sio, qse_mchar_t c)
{
qse_ssize_t n;
sio->errnum = QSE_SIO_ENOERR;
#if defined(__OS2__)
if (c == QSE_MT('\n') && (sio->status & STATUS_LINE_BREAK))
n = qse_tio_writembs (&sio->tio.io, QSE_MT("\r\n"), 2);
else
n = qse_tio_writembs (&sio->tio.io, &c, 1);
#else
n = qse_tio_writembs (&sio->tio.io, &c, 1);
#endif
if (n <= -1 && sio->errnum == QSE_SIO_ENOERR)
sio->errnum = tio_errnum_to_sio_errnum (&sio->tio.io);
return n;
}
qse_ssize_t qse_sio_putwc (qse_sio_t* sio, qse_wchar_t c)
{
qse_ssize_t n;
sio->errnum = QSE_SIO_ENOERR;
#if defined(__OS2__)
if (c == QSE_WT('\n') && (sio->status & STATUS_LINE_BREAK))
n = qse_tio_writewcs (&sio->tio.io, QSE_WT("\r\n"), 2);
else
n = qse_tio_writewcs (&sio->tio.io, &c, 1);
#else
n = qse_tio_writewcs (&sio->tio.io, &c, 1);
#endif
if (n <= -1 && sio->errnum == QSE_SIO_ENOERR)
sio->errnum = tio_errnum_to_sio_errnum (&sio->tio.io);
return n;
}
qse_ssize_t qse_sio_putmbs (qse_sio_t* sio, const qse_mchar_t* str)
{
qse_ssize_t n;
#if defined(_WIN32)
/* Using WriteConsoleA() didn't help at all.
* so I don't implement any hacks here */
#elif defined(__OS2__)
if (sio->status & STATUS_LINE_BREAK)
{
for (n = 0; n < QSE_TYPE_MAX(qse_ssize_t) && str[n] != QSE_MT('\0'); n++)
{
if ((n = qse_sio_putmb (sio, str[n])) <= -1) return n;
}
return n;
}
#endif
sio->errnum = QSE_SIO_ENOERR;
n = qse_tio_writembs (&sio->tio.io, str, (qse_size_t)-1);
if (n <= -1 && sio->errnum == QSE_SIO_ENOERR)
sio->errnum = tio_errnum_to_sio_errnum (&sio->tio.io);
return n;
}
qse_ssize_t qse_sio_putmbsn (
qse_sio_t* sio, const qse_mchar_t* str, qse_size_t size)
{
qse_ssize_t n;
#if defined(_WIN32)
/* Using WriteConsoleA() didn't help at all.
* so I don't implement any hacks here */
#elif defined(__OS2__)
if (sio->status & STATUS_LINE_BREAK)
{
if (size > QSE_TYPE_MAX(qse_ssize_t)) size = QSE_TYPE_MAX(qse_ssize_t);
for (n = 0; n < size; n++)
{
if (qse_sio_putmb (sio, str[n]) <= -1) return -1;
}
return n;
}
#endif
sio->errnum = QSE_SIO_ENOERR;
n = qse_tio_writembs (&sio->tio.io, str, size);
if (n <= -1 && sio->errnum == QSE_SIO_ENOERR)
sio->errnum = tio_errnum_to_sio_errnum (&sio->tio.io);
return n;
}
qse_ssize_t qse_sio_putwcs (qse_sio_t* sio, const qse_wchar_t* str)
{
qse_ssize_t n;
#if defined(_WIN32)
/* DAMN UGLY: See comment in qse_sio_putwcsn() */
if (sio->status & STATUS_UTF8_CONSOLE)
{
DWORD count, left;
const qse_wchar_t* cur;
if (qse_sio_flush (sio) <= -1) return -1; /* can't do buffering */
for (cur = str, left = qse_wcslen(str); left > 0; cur += count, left -= count)
{
if (WriteConsoleW (
sio->file.handle, cur, left,
&count, QSE_NULL) == FALSE)
{
sio->errnum = QSE_SIO_ESYSERR;
return -1;
}
if (count == 0) break;
if (count > left)
{
sio->errnum = QSE_SIO_ESYSERR;
return -1;
}
}
return cur - str;
}
#elif defined(__OS2__)
if (sio->status & STATUS_LINE_BREAK)
{
for (n = 0; n < QSE_TYPE_MAX(qse_ssize_t) && str[n] != QSE_WT('\0'); n++)
{
if (qse_sio_putwc (sio, str[n]) <= -1) return -1;
}
return n;
}
#endif
sio->errnum = QSE_SIO_ENOERR;
n = qse_tio_writewcs (&sio->tio.io, str, (qse_size_t)-1);
if (n <= -1 && sio->errnum == QSE_SIO_ENOERR)
sio->errnum = tio_errnum_to_sio_errnum (&sio->tio.io);
return n;
}
qse_ssize_t qse_sio_putwcsn (
qse_sio_t* sio, const qse_wchar_t* str, qse_size_t size)
{
qse_ssize_t n;
#if defined(_WIN32)
/* DAMN UGLY:
* WriteFile returns wrong number of bytes written if it is
* requested to write a utf8 string on utf8 console (codepage 65001).
* it seems to return a number of characters written instead. so
* i have to use an alternate API for console output for
* wide-character strings. Conversion to either an OEM codepage or
* the utf codepage is handled by the API. This hack at least
* lets you do proper utf8 output on utf8 console using wide-character.
*
* Note that the multibyte functions qse_sio_putmbs() and
* qse_sio_putmbsn() doesn't handle this. So you may still suffer.
*/
if (sio->status & STATUS_UTF8_CONSOLE)
{
DWORD count, left;
const qse_wchar_t* cur;
if (qse_sio_flush (sio) <= -1) return -1; /* can't do buffering */
for (cur = str, left = size; left > 0; cur += count, left -= count)
{
if (WriteConsoleW (
sio->file.handle, cur, left,
&count, QSE_NULL) == FALSE)
{
sio->errnum = QSE_SIO_ESYSERR;
return -1;
}
if (count == 0) break;
/* Note:
* WriteConsoleW() in unicosw.dll on win 9x/me returns
* the number of bytes via 'count'. If a double byte
* string is given, 'count' can be greater than 'left'.
* this case is a miserable failure. however, i don't
* think there is CP_UTF8 codepage for console on win9x/me.
* so let me make this function fail if that ever happens.
*/
if (count > left)
{
sio->errnum = QSE_SIO_ESYSERR;
return -1;
}
}
return cur - str;
}
#elif defined(__OS2__)
if (sio->status & STATUS_LINE_BREAK)
{
if (size > QSE_TYPE_MAX(qse_ssize_t)) size = QSE_TYPE_MAX(qse_ssize_t);
for (n = 0; n < size; n++)
{
if (qse_sio_putwc (sio, str[n]) <= -1) return -1;
}
return n;
}
#endif
sio->errnum = QSE_SIO_ENOERR;
n = qse_tio_writewcs (&sio->tio.io, str, size);
if (n <= -1 && sio->errnum == QSE_SIO_ENOERR)
sio->errnum = tio_errnum_to_sio_errnum (&sio->tio.io);
return n;
}
static int put_wchar (qse_wchar_t c, void* ctx)
{
return qse_sio_putwc ((qse_sio_t*)ctx, c);
}
static int put_mchar (qse_mchar_t c, void* ctx)
{
return qse_sio_putmb ((qse_sio_t*)ctx, c);
}
static int wcs_to_mbs (
const qse_wchar_t* wcs, qse_size_t* wcslen,
qse_mchar_t* mbs, qse_size_t* mbslen, void* ctx)
{
return qse_wcsntombsnwithcmgr (wcs, wcslen, mbs, mbslen, qse_sio_getcmgr ((qse_sio_t*)ctx));
}
static int mbs_to_wcs (
const qse_mchar_t* mbs, qse_size_t* mbslen,
qse_wchar_t* wcs, qse_size_t* wcslen, void* ctx)
{
return qse_mbsntowcsnwithcmgr (mbs, mbslen, wcs, wcslen, qse_sio_getcmgr ((qse_sio_t*)ctx));
}
qse_ssize_t qse_sio_putmbsf (qse_sio_t* sio, const qse_mchar_t* fmt, ...)
{
va_list ap;
qse_ssize_t x;
qse_mfmtout_t fo;
fo.limit = QSE_TYPE_MAX(qse_ssize_t);
fo.ctx = sio;
fo.put = put_mchar;
fo.conv = wcs_to_mbs;
va_start (ap, fmt);
x = qse_mfmtout (fmt, &fo, ap);
va_end (ap);
return (x <= -1)? -1: fo.count;
}
qse_ssize_t qse_sio_putwcsf (qse_sio_t* sio, const qse_wchar_t* fmt, ...)
{
va_list ap;
int x;
qse_wfmtout_t fo;
fo.limit = QSE_TYPE_MAX(qse_ssize_t);
fo.ctx = sio;
fo.put = put_wchar;
fo.conv = mbs_to_wcs;
va_start (ap, fmt);
x = qse_wfmtout (fmt, &fo, ap);
va_end (ap);
return (x <= -1)? -1: fo.count;
}
qse_ssize_t qse_sio_putmbsvf (qse_sio_t* sio, const qse_mchar_t* fmt, va_list ap)
{
qse_mfmtout_t fo;
fo.limit = QSE_TYPE_MAX(qse_ssize_t);
fo.ctx = sio;
fo.put = put_mchar;
fo.conv = wcs_to_mbs;
return (qse_mfmtout (fmt, &fo, ap) <= -1)? -1: fo.count;
}
qse_ssize_t qse_sio_putwcsvf (qse_sio_t* sio, const qse_wchar_t* fmt, va_list ap)
{
qse_wfmtout_t fo;
fo.limit = QSE_TYPE_MAX(qse_ssize_t);
fo.ctx = sio;
fo.put = put_wchar;
fo.conv = mbs_to_wcs;
return (qse_wfmtout (fmt, &fo, ap) <= -1)? -1: fo.count;
}
int qse_sio_getpos (qse_sio_t* sio, qse_sio_pos_t* pos)
{
qse_fio_off_t off;
if (qse_sio_flush(sio) <= -1) return -1;
off = qse_fio_seek (&sio->file, 0, QSE_FIO_CURRENT);
if (off == (qse_fio_off_t)-1)
{
sio->errnum = fio_errnum_to_sio_errnum (&sio->file);
return -1;
}
*pos = off;
return 0;
}
int qse_sio_setpos (qse_sio_t* sio, qse_sio_pos_t pos)
{
qse_fio_off_t off;
if (qse_sio_flush(sio) <= -1) return -1;
off = qse_fio_seek (&sio->file, pos, QSE_FIO_BEGIN);
if (off == (qse_fio_off_t)-1)
{
sio->errnum = fio_errnum_to_sio_errnum (&sio->file);
return -1;
}
return 0;
}
int qse_sio_truncate (qse_sio_t* sio, qse_sio_pos_t pos)
{
if (qse_sio_flush(sio) <= -1) return -1;
return qse_fio_truncate (&sio->file, pos);
}
int qse_sio_seek (qse_sio_t* sio, qse_sio_pos_t* pos, qse_sio_ori_t origin)
{
qse_fio_off_t x;
if (qse_sio_flush(sio) <= -1) return -1;
x = qse_fio_seek (&sio->file, *pos, origin);
if (x == (qse_fio_off_t)-1) return -1;
*pos = x;
return 0;
}
static qse_ssize_t file_input (
qse_tio_t* tio, qse_tio_cmd_t cmd, void* buf, qse_size_t size)
{
if (cmd == QSE_TIO_DATA)
{
qse_ssize_t n;
qse_sio_t* sio;
sio = *(qse_sio_t**)QSE_XTN(tio);
QSE_ASSERT (sio != QSE_NULL);
n = qse_fio_read (&sio->file, buf, size);
if (n <= -1) sio->errnum = fio_errnum_to_sio_errnum (&sio->file);
return n;
}
return 0;
}
static qse_ssize_t file_output (
qse_tio_t* tio, qse_tio_cmd_t cmd, void* buf, qse_size_t size)
{
if (cmd == QSE_TIO_DATA)
{
qse_ssize_t n;
qse_sio_t* sio;
sio = *(qse_sio_t**)QSE_XTN(tio);
QSE_ASSERT (sio != QSE_NULL);
n = qse_fio_write (&sio->file, buf, size);
if (n <= -1) sio->errnum = fio_errnum_to_sio_errnum (&sio->file);
return n;
}
return 0;
}
/* ---------------------------------------------------------- */
static qse_sio_t* sio_stdout = QSE_NULL;
static qse_sio_t* sio_stderr = QSE_NULL;
/* TODO: add sio_stdin, qse_getmbs, etc */
int qse_openstdsios (void)
{
if (sio_stdout == QSE_NULL)
{
sio_stdout = qse_sio_openstd (QSE_MMGR_GETDFL(), 0, QSE_SIO_STDOUT, QSE_SIO_LINEBREAK);
}
if (sio_stderr == QSE_NULL)
{
sio_stderr = qse_sio_openstd (QSE_MMGR_GETDFL(), 0, QSE_SIO_STDERR, QSE_SIO_LINEBREAK);
}
if (sio_stdout == QSE_NULL || sio_stderr == QSE_NULL)
{
qse_closestdsios ();
return -1;
}
return 0;
}
void qse_closestdsios (void)
{
if (sio_stderr)
{
qse_sio_close (sio_stderr);
sio_stderr = QSE_NULL;
}
if (sio_stdout)
{
qse_sio_close (sio_stdout);
sio_stdout = QSE_NULL;
}
}
qse_sio_t* qse_getstdout (void)
{
return sio_stdout;
}
qse_sio_t* qse_getstderr (void)
{
return sio_stderr;
}
qse_ssize_t qse_putmbsf (const qse_mchar_t* fmt, ...)
{
va_list ap;
int x;
qse_mfmtout_t fo;
fo.limit = QSE_TYPE_MAX(qse_ssize_t);
fo.ctx = sio_stdout;
fo.put = put_mchar;
fo.conv = wcs_to_mbs;
va_start (ap, fmt);
x = qse_mfmtout (fmt, &fo, ap);
va_end (ap);
return (x <= -1)? -1: fo.count;
}
qse_ssize_t qse_putwcsf (const qse_wchar_t* fmt, ...)
{
va_list ap;
int x;
qse_wfmtout_t fo;
fo.limit = QSE_TYPE_MAX(qse_ssize_t);
fo.ctx = sio_stdout;
fo.put = put_wchar;
fo.conv = mbs_to_wcs;
va_start (ap, fmt);
x = qse_wfmtout (fmt, &fo, ap);
va_end (ap);
return (x <= -1)? -1: fo.count;
}
qse_ssize_t qse_putmbsvf (const qse_mchar_t* fmt, va_list ap)
{
qse_mfmtout_t fo;
fo.limit = QSE_TYPE_MAX(qse_ssize_t);
fo.ctx = sio_stdout;
fo.put = put_mchar;
fo.conv = wcs_to_mbs;
return (qse_mfmtout (fmt, &fo, ap) <= -1)? -1: fo.count;
}
qse_ssize_t qse_putwcsvf (const qse_wchar_t* fmt, va_list ap)
{
qse_wfmtout_t fo;
fo.limit = QSE_TYPE_MAX(qse_ssize_t);
fo.ctx = sio_stdout;
fo.put = put_wchar;
fo.conv = mbs_to_wcs;
return (qse_wfmtout (fmt, &fo, ap) <= -1)? -1: fo.count;
}
qse_ssize_t qse_errputmbsf (const qse_mchar_t* fmt, ...)
{
va_list ap;
int x;
qse_mfmtout_t fo;
fo.limit = QSE_TYPE_MAX(qse_ssize_t);
fo.ctx = sio_stderr;
fo.put = put_mchar;
fo.conv = wcs_to_mbs;
va_start (ap, fmt);
x = qse_mfmtout (fmt, &fo, ap);
va_end (ap);
return (x <= -1)? -1: fo.count;
}
qse_ssize_t qse_errputwcsf (const qse_wchar_t* fmt, ...)
{
va_list ap;
int x;
qse_wfmtout_t fo;
fo.limit = QSE_TYPE_MAX(qse_ssize_t);
fo.ctx = sio_stderr;
fo.put = put_wchar;
fo.conv = mbs_to_wcs;
va_start (ap, fmt);
x = qse_wfmtout (fmt, &fo, ap);
va_end (ap);
return (x <= -1)? -1: fo.count;
}
qse_ssize_t qse_errputmbsvf (const qse_mchar_t* fmt, va_list ap)
{
qse_mfmtout_t fo;
fo.limit = QSE_TYPE_MAX(qse_ssize_t);
fo.ctx = sio_stderr;
fo.put = put_mchar;
fo.conv = wcs_to_mbs;
return (qse_mfmtout (fmt, &fo, ap) <= -1)? -1: fo.count;
}
qse_ssize_t qse_errputwcsvf (const qse_wchar_t* fmt, va_list ap)
{
qse_wfmtout_t fo;
fo.limit = QSE_TYPE_MAX(qse_ssize_t);
fo.ctx = sio_stderr;
fo.put = put_wchar;
fo.conv = mbs_to_wcs;
return (qse_wfmtout (fmt, &fo, ap) <= -1)? -1: fo.count;
}

644
qse/lib/si/task.c Normal file
View File

@ -0,0 +1,644 @@
/*
* $Id$
*
Copyright (c) 2006-2014 Chung, Hyung-Hwan. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <qse/si/task.h>
#include "../cmn/mem.h"
#if defined(_WIN64)
# if !defined(_WIN32_WINNT)
# define _WIN32_WINNT 0x0400
# endif
# include <windows.h>
#else
# include <setjmp.h>
# if defined(HAVE_UCONTEXT_H)
# include <ucontext.h>
# endif
# if defined(HAVE_MAKECONTEXT) && defined(HAVE_SWAPCONTEXT) && \
defined(HAVE_GETCONTEXT) && defined(HAVE_SETCONTEXT)
# define USE_UCONTEXT
# endif
#endif
struct qse_task_t
{
qse_mmgr_t* mmgr;
qse_task_slice_t* dead;
qse_task_slice_t* current;
qse_size_t count;
qse_task_slice_t* head;
qse_task_slice_t* tail;
#if defined(_WIN64)
void* fiber;
#elif defined(USE_UCONTEXT)
ucontext_t uctx;
#else
jmp_buf backjmp;
#endif
};
struct qse_task_slice_t
{
#if defined(_WIN64)
void* fiber;
#elif defined(USE_UCONTEXT)
ucontext_t uctx;
#else
jmp_buf jmpbuf;
#endif
qse_task_t* task;
int id;
qse_task_fnc_t fnc;
void* ctx;
qse_size_t stksize;
qse_task_slice_t* prev;
qse_task_slice_t* next;
};
int qse_task_init (qse_task_t* task, qse_mmgr_t* mmgr);
void qse_task_fini (qse_task_t* task);
static void purge_slice (qse_task_t* task, qse_task_slice_t* slice);
static void purge_dead_slices (qse_task_t* task);
static void purge_current_slice (qse_task_slice_t* slice, qse_task_slice_t* to);
qse_task_t* qse_task_open (qse_mmgr_t* mmgr, qse_size_t xtnsize)
{
qse_task_t* task;
task = QSE_MMGR_ALLOC (mmgr, QSE_SIZEOF(*task) + xtnsize);
if (task == QSE_NULL) return QSE_NULL;
if (qse_task_init (task, mmgr) <= -1)
{
QSE_MMGR_FREE (task->mmgr, task);
return QSE_NULL;
}
QSE_MEMSET (task + 1, 0, xtnsize);
return task;
}
void qse_task_close (qse_task_t* task)
{
qse_task_fini (task);
QSE_MMGR_FREE (task->mmgr, task);
}
int qse_task_init (qse_task_t* task, qse_mmgr_t* mmgr)
{
QSE_MEMSET (task, 0, QSE_SIZEOF(*task));
task->mmgr = mmgr;
return 0;
}
void qse_task_fini (qse_task_t* task)
{
QSE_ASSERT (task->dead == QSE_NULL);
QSE_ASSERT (task->current == QSE_NULL);
if (task->count > 0)
{
/* am i closing after boot failure? */
qse_task_slice_t* slice, * next;
slice = task->head;
while (slice)
{
next = slice->next;
purge_slice (task, slice);
slice = next;
}
task->count = 0;
task->head = QSE_NULL;
task->tail = QSE_NULL;
}
}
qse_mmgr_t* qse_task_getmmgr (qse_task_t* task)
{
return task->mmgr;
}
void* qse_task_getxtn (qse_task_t* task)
{
return (void*)(task + 1);
}
static qse_task_slice_t* alloc_slice (
qse_task_t* task, qse_task_fnc_t fnc,
void* ctx, qse_size_t stksize)
{
qse_task_slice_t* slice;
slice = QSE_MMGR_ALLOC (task->mmgr, QSE_SIZEOF(*slice) + stksize);
if (slice == QSE_NULL) return QSE_NULL;
QSE_MEMSET (slice, 0, QSE_SIZEOF(*slice));
slice->task = task;
slice->fnc = fnc;
slice->ctx = ctx;
slice->stksize = stksize;
return slice;
}
static void link_task (qse_task_t* task, qse_task_slice_t* slice)
{
if (task->head)
{
slice->next = task->head;
task->head->prev = slice;
task->head = slice;
}
else
{
task->head = slice;
task->tail = slice;
}
task->count++;
}
#if defined(_WIN64)
# define __CALL_BACK__ __stdcall
#else
# define __CALL_BACK__
#endif
#if defined(USE_UCONTEXT) && \
(QSE_SIZEOF_INT == QSE_SIZEOF_INT32_T) && \
(QSE_SIZEOF_VOID_P == (QSE_SIZEOF_INT32_T * 2))
static void __CALL_BACK__ execute_current_slice (qse_uint32_t ptr1, qse_uint32_t ptr2)
{
qse_task_slice_t* slice;
qse_task_slice_t* to;
slice = (qse_task_slice_t*)(((qse_uintptr_t)ptr1 << 32) | ptr2);
QSE_ASSERT (slice->task->current == slice);
to = slice->fnc (slice->task, slice, slice->ctx);
/* the task function is now terminated. we need to
* purge it from the slice list and switch to the next
* slice. */
purge_current_slice (slice, to);
QSE_ASSERT (!"must never reach here...");
}
#else
static void __CALL_BACK__ execute_current_slice (qse_task_slice_t* slice)
{
qse_task_slice_t* to;
QSE_ASSERT (slice->task->current == slice);
to = slice->fnc (slice->task, slice, slice->ctx);
/* the task function is now terminated. we need to
* purge it from the slice list and switch to the next
* slice. */
purge_current_slice (slice, to);
QSE_ASSERT (!"must never reach here...");
}
#endif
#if defined(__WATCOMC__)
/* for watcom, i support i386/32bit only */
extern void* prepare_sp (void*);
#pragma aux prepare_sp = \
"mov dword ptr[eax+4], esp" \
"mov esp, eax" \
"mov eax, dword ptr[esp+0]" \
parm [eax] value [eax] modify [esp]
extern void* restore_sp (void);
#pragma aux restore_sp = \
"mov esp, dword ptr[esp+4]" \
modify [esp]
extern void* get_slice (void);
#pragma aux get_slice = \
"mov eax, dword ptr[esp+0]" \
value [eax]
#endif
qse_task_slice_t* qse_task_create (
qse_task_t* task, qse_task_fnc_t fnc,
void* ctx, qse_size_t stksize)
{
qse_task_slice_t* slice;
register void* tmp;
stksize = ((stksize + QSE_SIZEOF(void*) - 1) / QSE_SIZEOF(void*)) * QSE_SIZEOF(void*);
#if defined(_WIN64)
slice = alloc_slice (task, fnc, ctx, 0);
if (slice == QSE_NULL) return QSE_NULL;
slice->fiber = CreateFiberEx (
stksize, stksize, FIBER_FLAG_FLOAT_SWITCH,
execute_current_slice, slice);
if (slice->fiber == QSE_NULL)
{
QSE_MMGR_FREE (task->mmgr, slice);
return QSE_NULL;
}
#elif defined(USE_UCONTEXT)
slice = alloc_slice (task, fnc, ctx, stksize);
if (slice == QSE_NULL) return QSE_NULL;
if (getcontext (&slice->uctx) <= -1)
{
QSE_MMGR_FREE (task->mmgr, slice);
return QSE_NULL;
}
slice->uctx.uc_stack.ss_sp = slice + 1;
slice->uctx.uc_stack.ss_size = stksize;
slice->uctx.uc_link = QSE_NULL;
#if (QSE_SIZEOF_INT == QSE_SIZEOF_INT32_T) && \
(QSE_SIZEOF_VOID_P == (QSE_SIZEOF_INT32_T * 2))
/* limited work around for unclear makecontext parameters */
makecontext (&slice->uctx, execute_current_slice, 2,
(qse_uint32_t)(((qse_uintptr_t)slice) >> 32),
(qse_uint32_t)((qse_uintptr_t)slice & 0xFFFFFFFFu));
#else
makecontext (&slice->uctx, execute_current_slice, 1, slice);
#endif
#else
if (stksize < QSE_SIZEOF(void*) * 3)
stksize = QSE_SIZEOF(void*) * 3; /* for t1 & t2 */
slice = alloc_slice (task, fnc, ctx, stksize);
if (slice == QSE_NULL) return QSE_NULL;
/* setjmp() doesn't allow different stacks for
* each execution content. let me use some assembly
* to change the stack pointer so that setjmp() remembers
* the new stack pointer for longjmp() later.
*
* this stack is used for the task function when
* longjmp() is made. */
tmp = ((qse_uint8_t*)(slice + 1)) + stksize - QSE_SIZEOF(void*);
tmp = (qse_uint8_t*)tmp - QSE_SIZEOF(void*);
*(void**)tmp = QSE_NULL; /* t1 */
tmp = (qse_uint8_t*)tmp - QSE_SIZEOF(void*);
*(void**)tmp = slice; /* t2 */
#if defined(__WATCOMC__)
tmp = prepare_sp (tmp);
#elif defined(__GNUC__) && (defined(__x86_64) || defined(__amd64))
__asm__ volatile (
"movq %%rsp, 8(%1)\n\t" /* t1 = %rsp */
"movq %1, %%rsp\n\t" /* %rsp = tmp */
"movq 0(%%rsp), %0\n" /* tmp = t2 */
: "=r"(tmp)
: "0"(tmp)
: "%rsp", "memory"
);
#elif defined(__GNUC__) && (defined(__i386) || defined(i386))
__asm__ volatile (
"movl %%esp, 4(%1)\n\t" /* t1 = %esp */
"movl %1, %%esp\n\t" /* %esp = tmp */
"movl 0(%%esp), %0\n" /* tmp = t2 */
: "=r"(tmp)
: "0"(tmp)
: "%esp", "memory"
);
#elif defined(__GNUC__) && (defined(__mips) || defined(mips))
__asm__ volatile (
"sw $sp, 4(%1)\n\t" /* t1 = $sp */
"move $sp, %1\n\t" /* %sp = tmp */
"lw %0, 0($sp)\n" /* tmp = t2 */
: "=r"(tmp)
: "0"(tmp)
: "$sp", "memory"
);
#elif defined(__GNUC__) && defined(__arm__)
__asm__ volatile (
"str sp, [%1, #4]\n\t" /* t1 = sp */
"mov sp, %1\n" /* sp = tmp */
"ldr %0, [sp, #0]\n" /* tmp = t2 */
: "=r"(tmp)
: "0"(tmp)
: "sp", "memory"
);
#else
/* TODO: support more architecture */
QSE_MMGR_FREE (task->mmgr, task);
return QSE_NULL;
#endif /* __WATCOMC__ */
/*
* automatic variables like 'task' and 'newsp' exist
* in the old stack. i can't access them.
* i access some key informaton via the global
* variables stored before stack pointer switching.
*
* this approach makes this function thread-unsafe.
*/
/* when qse_task_create() is called,
* setjmp() saves the context and return 0.
*
* subsequently, when longjmp() is made
* for this saved context, setjmp() returns
* a non-zero value.
*/
if (setjmp (((qse_task_slice_t*)tmp)->jmpbuf) != 0)
{
/* longjmp() is made to here. */
#if defined(__WATCOMC__)
tmp = get_slice ();
#elif defined(__GNUC__) && (defined(__x86_64) || defined(__amd64))
__asm__ volatile (
"movq 0(%%rsp), %0\n" /* tmp = t2 */
: "=r"(tmp)
);
#elif defined(__GNUC__) && (defined(__i386) || defined(i386))
__asm__ volatile (
"movl 0(%%esp), %0\n" /* tmp = t2 */
: "=r"(tmp)
);
#elif defined(__GNUC__) && (defined(__mips) || defined(mips))
__asm__ volatile (
"lw %0, 0($sp)\n" /* tmp = t2 */
: "=r"(tmp)
);
#elif defined(__GNUC__) && defined(__arm__)
__asm__ volatile (
"ldr %0, [sp, #0]\n" /* tmp = t2 */
: "=r"(tmp)
);
#endif /* __WATCOMC__ */
execute_current_slice ((qse_task_slice_t*)tmp);
QSE_ASSERT (!"must never reach here....\n");
}
/* restore the stack pointer once i finish saving the longjmp() context.
* this part is reached only when qse_task_create() is invoked. */
#if defined(__WATCOMC__)
restore_sp ();
#elif defined(__GNUC__) && (defined(__x86_64) || defined(__amd64))
/* i assume that %rsp didn't change after the call to setjmp() */
__asm__ volatile (
"movq 8(%%rsp), %%rsp\n" /* %rsp = t1 */
:
:
: "%rsp"
);
#elif defined(__GNUC__) && (defined(__i386) || defined(i386))
__asm__ volatile (
"movl 4(%%esp), %%esp\n" /* %esp = t1 */
:
:
: "%esp"
);
#elif defined(__GNUC__) && (defined(__mips) || defined(mips))
__asm__ volatile (
"lw $sp, 4($sp)\n" /* $sp = t1 */
:
:
: "$sp"
);
#elif defined(__GNUC__) && defined(__arm__)
__asm__ volatile (
"ldr sp, [sp, #4]\n" /* sp = t1 */
:
:
: "sp"
);
#endif /* __WATCOMC__ */
#endif
link_task (task, slice);
return slice;
}
int qse_task_boot (qse_task_t* task, qse_task_slice_t* to)
{
QSE_ASSERT (task->current == QSE_NULL);
if (to == QSE_NULL) to = task->head;
#if defined(_WIN64)
task->fiber = ConvertThreadToFiberEx (QSE_NULL, FIBER_FLAG_FLOAT_SWITCH);
if (task->fiber == QSE_NULL) return -1;
task->current = to;
SwitchToFiber (task->current->fiber);
ConvertFiberToThread ();
#elif defined(USE_UCONTEXT)
task->current = to;
if (swapcontext (&task->uctx, &task->current->uctx) <= -1)
{
task->current = QSE_NULL;
return -1;
}
#else
if (setjmp (task->backjmp) != 0)
{
/* longjmp() back */
goto done;
}
task->current = to;
longjmp (task->current->jmpbuf, 1);
QSE_ASSERT (!"must never reach here");
done:
#endif
QSE_ASSERT (task->current == QSE_NULL);
QSE_ASSERT (task->count == 0);
if (task->dead) purge_dead_slices (task);
return 0;
}
/* NOTE for __WATCOMC__.
when the number of parameters is more than 2 for qse_task_schedule(),
this setjmp()/longjmp() based tasking didn't work.
if i change this to
void qse_task_schedule (qse_task_slice_t* from, qse_task_slice_t* to)
{
qse_task_t* task = from->task
....
}
it worked. i stopped investigating this problem. so i don't know the
real cause of this problem. let me get back to this later when i have
time for this.
*/
void qse_task_schedule (
qse_task_t* task, qse_task_slice_t* from, qse_task_slice_t* to)
{
QSE_ASSERT (from != QSE_NULL);
if (to == QSE_NULL)
{
/* round-robin if the target is not specified */
to = from->next? from->next: task->head;
}
QSE_ASSERT (task == to->task);
QSE_ASSERT (task == from->task);
QSE_ASSERT (task->current == from);
if (to == from) return;
task->current = to;
#if defined(_WIN64)
/* current->fiber is handled by SwitchToFiber() implicitly */
SwitchToFiber (to->fiber);
if (task->dead) purge_dead_slices (task);
#elif defined(USE_UCONTEXT)
swapcontext (&from->uctx, &to->uctx);
if (task->dead) purge_dead_slices (task);
#else
if (setjmp (from->jmpbuf) != 0)
{
if (task->dead) purge_dead_slices (task);
return;
}
longjmp (to->jmpbuf, 1);
#endif
}
static void purge_dead_slices (qse_task_t* task)
{
qse_task_slice_t* slice;
while (task->dead)
{
slice = task->dead;
task->dead = slice->next;
purge_slice (task, slice);
}
}
static void purge_slice (qse_task_t* task, qse_task_slice_t* slice)
{
#if defined(_WIN64)
if (slice->fiber) DeleteFiber (slice->fiber);
#endif
QSE_MMGR_FREE (task->mmgr, slice);
}
static void purge_current_slice (qse_task_slice_t* slice, qse_task_slice_t* to)
{
qse_task_t* task = slice->task;
QSE_ASSERT (task->current == slice);
if (task->count == 1)
{
/* to purge later */
slice->next = task->dead;
task->dead = slice;
task->current = QSE_NULL;
task->head = QSE_NULL;
task->tail = QSE_NULL;
task->count = 0;
#if defined(_WIN64)
SwitchToFiber (task->fiber);
#elif defined(USE_UCONTEXT)
setcontext (&task->uctx);
#else
longjmp (task->backjmp, 1);
#endif
QSE_ASSERT (!"must not reach here....");
}
task->current = (to && to != slice)? to: (slice->next? slice->next: task->head);
if (slice->prev) slice->prev->next = slice->next;
if (slice->next) slice->next->prev = slice->prev;
if (slice == task->head) task->head = slice->next;
if (slice == task->tail) task->tail = slice->prev;
task->count--;
/* to purge later */
slice->next = task->dead;
task->dead = slice;
#if defined(_WIN64)
SwitchToFiber (task->current->fiber);
#elif defined(USE_UCONTEXT)
setcontext (&task->current->uctx);
#else
longjmp (task->current->jmpbuf, 1);
#endif
}

84
qse/lib/si/thr-prv.h Normal file
View File

@ -0,0 +1,84 @@
/*
* $Id$
*
Copyright (c) 2006-2014 Chung, Hyung-Hwan. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _QSE_LIB_CMN_THR_H_
#define _QSE_LIB_CMN_THR_H_
#include <qse/si/thr.h>
#if (!defined(__unix__) && !defined(__unix)) || defined(HAVE_PTHREAD)
#if defined(_WIN32)
# include <windows.h>
# include <process.h>
# define QSE_THR_HND_INVALID INVALID_HANDLE_VALUE
#elif defined(__OS2__)
# define INCL_DOSPROCESS
# define INCL_DOSDATETIME
# define INCL_DOSERRORS
# include <os2.h>
# include <process.h>
# define QSE_THR_HND_INVALID (-1)
#elif defined(__DOS__)
/* not implemented */
#elif defined(__BEOS__)
# include <be/kernel/OS.h>
# define QSE_THR_HND_INVALID (-1)
#else
# if defined(AIX) && defined(__GNUC__)
typedef int crid_t;
typedef unsigned int class_id_t;
# endif
# include <pthread.h>
# include <signal.h>
# define QSE_THR_HND_INVALID 0
#endif
struct qse_thr_t
{
qse_mmgr_t* mmgr;
qse_thr_routine_t __main_routine;
qse_thr_routine_t __temp_routine;
qse_bool_t __joinable;
qse_size_t __stacksize;
qse_thr_hnd_t __handle;
qse_thr_state_t __state;
int __return_code;
};
#endif
#endif

430
qse/lib/si/thr.c Normal file
View File

@ -0,0 +1,430 @@
/*
* $Id$
*
Copyright (c) 2006-2014 Chung, Hyung-Hwan. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "thr-prv.h"
#include "../cmn/mem.h"
#include <qse/cmn/time.h>
#include <stdarg.h>
#if (!defined(__unix__) && !defined(__unix)) || defined(HAVE_PTHREAD)
qse_thr_t* qse_thr_open (qse_mmgr_t* mmgr, qse_size_t xtnsize, qse_thr_routine_t routine)
{
qse_thr_t* thr;
thr = (qse_thr_t*) QSE_MMGR_ALLOC (mmgr, QSE_SIZEOF(qse_thr_t) + xtnsize);
if (thr)
{
if (qse_thr_init (thr, mmgr, routine) <= -1)
{
QSE_MMGR_FREE (mmgr, thr);
return QSE_NULL;
}
else QSE_MEMSET (QSE_XTN(thr), 0, xtnsize);
}
return thr;
}
void qse_thr_close (qse_thr_t* thr)
{
qse_thr_fini (thr);
QSE_MMGR_FREE (thr->mmgr, thr);
}
int qse_thr_init (qse_thr_t* thr, qse_mmgr_t* mmgr, qse_thr_routine_t routine)
{
QSE_MEMSET (thr, 0, QSE_SIZEOF(*thr));
thr->mmgr = mmgr;
thr->__handle = QSE_THR_HND_INVALID;
thr->__state = QSE_THR_INCUBATING;
thr->__return_code = 0;
thr->__main_routine = routine;
thr->__joinable = 1;
thr->__stacksize = 0;
return 0;
}
void qse_thr_fini (qse_thr_t* thr)
{
#if defined(_WIN32)
if (thr->__handle != QSE_THR_HND_INVALID) CloseHandle (thr->__handle);
#endif
thr->__handle = QSE_THR_HND_INVALID;
}
qse_mmgr_t* qse_thr_getmmgr (qse_thr_t* thr)
{
return thr->mmgr;
}
void* qse_thr_getxtn (qse_thr_t* thr)
{
return QSE_XTN (thr);
}
qse_size_t qse_thr_getstacksize (qse_thr_t* thr)
{
return thr->__stacksize;
}
void qse_thr_setstacksize (qse_thr_t* thr, qse_size_t num)
{
thr->__stacksize = num;
}
#if defined(__OS2__)
static void __thread_main (void* arg)
#elif defined(__BEOS__)
static int32 __thread_main (void* arg)
#else
static void* __thread_main (void* arg)
#endif
{
qse_thr_t* thr = (qse_thr_t*)arg;
while (thr->__state != QSE_THR_RUNNING)
{
#if defined(_WIN32)
Sleep (0);
#elif defined(__OS2__)
DosSleep (0);
#elif defined(HAVE_NANOSLEEP)
struct timespec ts;
ts.tv_sec = 0;
ts.tv_nsec = 0;
nanosleep (&ts, &ts);
#else
sleep (0);
#endif
}
#if defined(HAVE_PTHREAD)
/*
* the asynchronous cancel-type is used to better emulate
* the bad effect of WIN32's TerminateThread using pthread_cancel
*/
pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, QSE_NULL);
pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, QSE_NULL);
#endif
thr->__return_code = thr->__temp_routine? thr->__temp_routine(thr): thr->__main_routine(thr);
thr->__state = QSE_THR_TERMINATED;
#if defined(_WIN32)
_endthreadex (thr->__return_code);
return QSE_NULL;
#elif defined(__OS2__)
_endthread ();
/* no return statement */
#elif defined(__DOS__)
/* not implemented */
return QSE_NULL;
#elif defined(__BEOS__)
exit_thread (thr->__return_code);
return 0;
#else
pthread_exit (&thr->__return_code);
return QSE_NULL;
#endif
}
static int __create_thread (qse_thr_t* thr)
{
#if defined(_WIN32)
unsigned int tid;
if (thr->__handle != QSE_THR_HND_INVALID) CloseHandle (thr->__handle);
thr->__handle = (HANDLE)_beginthreadex (QSE_NULL, 0, (unsigned int (__stdcall*)(void*))__thread_main, thr, 0, &tid);
if (thr->__handle == 0) return -1;
#elif defined(__OS2__)
TID tid;
/* default stack size to 81920(4096 * 20) */
tid = _beginthread (__thread_main, NULL, (thr->__stacksize > 0? thr->__stacksize: 81920), thr);
if (tid == -1) return -1;
thr->__handle = tid;
#elif defined(__DOS__)
/* not implemented */
#elif defined(__BEOS__)
thread_id tid;
tid = spawn_thread ((thread_func)__thread_main, QSE_NULL, 120, thr);
if (tid < B_OK) return -1;
thr->__handle = tid;
resume_thread(thr->__handle);
#elif defined(HAVE_PTHREAD)
pthread_attr_t attr;
pthread_attr_init (&attr);
if (pthread_attr_setdetachstate (&attr, (thr->__joinable?
PTHREAD_CREATE_JOINABLE: PTHREAD_CREATE_DETACHED)) != 0)
{
pthread_attr_destroy (&attr);
return -1;
}
if (thr->__stacksize > 0)
{
if (pthread_attr_setstacksize (&attr, thr->__stacksize) != 0)
{
pthread_attr_destroy (&attr);
return -1;
}
}
if (pthread_create (&thr->__handle, &attr, __thread_main, thr) != 0)
{
pthread_attr_destroy (&attr);
return -1;
}
pthread_attr_destroy (&attr);
#endif
return 0;
}
static int __cancel_thread (qse_thr_t* thr)
{
if (thr->__state != QSE_THR_RUNNING) return -1;
#if defined(_WIN32)
if (TerminateThread (thr->__handle, 0) == 0) return -1;
#elif defined(__OS2__)
if (DosKillThread (thr->__handle) != NO_ERROR) return -1;
#elif defined(__DOS__)
/* not implemented */
#elif defined(__BEOS__)
if (kill_thread (thr->__handle) < B_OK) return -1;
#elif defined(HAVE_PTHREAD)
if (pthread_cancel (thr->__handle) != 0) return -1;
#endif
return 0;
}
int qse_thr_start (qse_thr_t* thr, int flags, ...)
{
if (thr->__state == QSE_THR_RUNNING) return -1;
thr->__joinable = ((flags & QSE_THR_DETACHED) == 0);
if (flags & QSE_THR_NEW_ROUTINE)
{
va_list va;
va_start (va, flags);
thr->__temp_routine = va_arg (va, qse_thr_routine_t);
va_end (va);
}
else thr->__temp_routine = QSE_NULL;
if (__create_thread(thr) == -1)
{
thr->__state = QSE_THR_INCUBATING;
thr->__handle = QSE_THR_HND_INVALID;
return -1;
}
thr->__state = QSE_THR_RUNNING;
return 0;
}
int qse_thr_stop (qse_thr_t* thr)
{
if (thr->__state == QSE_THR_RUNNING)
{
if (__cancel_thread(thr) == -1) return -1;
/* can't be sure of whether or not the thread is really terminated. */
thr->__state = QSE_THR_ABORTED;
return 0;
}
return -1;
}
int qse_thr_join (qse_thr_t* thr)
{
if (thr->__state == QSE_THR_INCUBATING) return -1;
if (!thr->__joinable) return -1;
#if defined(_WIN32)
if (thr->__state == QSE_THR_RUNNING)
{
if (WaitForSingleObject (thr->__handle, INFINITE) == WAIT_FAILED) return -1;
}
#elif defined(__OS2__)
if (DosWaitThread (&thr->__handle, DCWW_WAIT) != NO_ERROR) return -1;
#elif defined(__DOS__)
/* not implemented */
#elif defined(__BEOS__)
if (wait_for_thread(thr->__handle, QSE_NULL) < B_OK) return -1;
#elif defined(HAVE_PTHREAD)
if (pthread_join(thr->__handle, QSE_NULL) != 0) return -1;
#endif
thr->__joinable = 0;
return 0;
}
int qse_thr_detach (qse_thr_t* thr)
{
if (thr->__state == QSE_THR_INCUBATING) return -1;
if (!thr->__joinable) return -1;
#if defined(HAVE_PTHREAD)
if (pthread_detach(thr->__handle) != 0) return -1;
#endif
thr->__joinable = 0;
return 0;
}
int qse_thr_kill (qse_thr_t* thr, int sig)
{
/* this function is to send a signal to a thread.
* don't get confused by the name */
if (thr->__state != QSE_THR_RUNNING) return -1;
#if defined(HAVE_PTHREAD)
if (pthread_kill (thr->__handle, sig) != 0) return -1;
#endif
return 0;
}
int qse_thr_blocksig (qse_thr_t* thr, int sig)
{
#if defined(HAVE_PTHREAD)
sigset_t mask;
#endif
if (thr->__state != QSE_THR_RUNNING) return -1;
#if defined(HAVE_PTHREAD)
sigemptyset (&mask);
sigaddset (&mask, sig);
if (pthread_sigmask (SIG_BLOCK, &mask, QSE_NULL) != 0) return -1;
#endif
return 0;
}
int qse_thr_unblocksig (qse_thr_t* thr, int sig)
{
#if defined(HAVE_PTHREAD)
sigset_t mask;
#endif
if (thr->__state != QSE_THR_RUNNING) return -1;
#if defined(HAVE_PTHREAD)
sigemptyset (&mask);
sigaddset (&mask, sig);
if (pthread_sigmask (SIG_UNBLOCK, &mask, QSE_NULL) != 0) return -1;
#endif
return 0;
}
int qse_thr_blockallsigs (qse_thr_t* thr)
{
#if defined(HAVE_PTHREAD)
sigset_t mask;
#endif
if (thr->__state != QSE_THR_RUNNING) return -1;
#if defined(HAVE_PTHREAD)
sigfillset (&mask);
if (pthread_sigmask (SIG_BLOCK, &mask, QSE_NULL) != 0) return -1;
#endif
return 0;
}
int qse_thr_unblockallsigs (qse_thr_t* thr)
{
#if defined(HAVE_PTHREAD)
sigset_t mask;
#endif
if (thr->__state != QSE_THR_RUNNING) return -1;
#if defined(HAVE_PTHREAD)
sigfillset (&mask);
if (pthread_sigmask (SIG_UNBLOCK, &mask, QSE_NULL) != 0) return -1;
#endif
return 0;
}
qse_thr_hnd_t qse_thr_gethnd (qse_thr_t* thr)
{
return thr->__handle;
}
int qse_thr_getretcode (qse_thr_t* thr)
{
return thr->__return_code;
}
qse_thr_state_t qse_thr_getstate (qse_thr_t* thr)
{
return thr->__state;
}
qse_thr_hnd_t qse_getcurthrhnd (void)
{
#if defined(_WIN32)
return GetCurrentThread ();
#elif defined(__OS2__)
PTIB ptib;
PPIB ppib;
if (DosGetInfoBlocks (&ptib, &ppib) != NO_ERROR) return QSE_THR_HND_INVALID;
return ptib->tib_ptib2->tib2_ultid;
#elif defined(__DOS__)
return QSE_THR_HND_INVALID; /* TODO: implement this */
#elif defined(__BEOS__)
return QSE_THR_HND_INVALID; /* TODO: implement this */
#else
return pthread_self ();
#endif
}
#endif

759
qse/lib/si/tio.c Normal file
View File

@ -0,0 +1,759 @@
/*
* $Id$
*
Copyright (c) 2006-2014 Chung, Hyung-Hwan. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <qse/si/tio.h>
#include <qse/cmn/mbwc.h>
#include "../cmn/mem.h"
#define STATUS_OUTPUT_DYNBUF (1 << 0)
#define STATUS_INPUT_DYNBUF (1 << 1)
#define STATUS_INPUT_ILLSEQ (1 << 2)
#define STATUS_INPUT_EOF (1 << 3)
static int detach_in (qse_tio_t* tio, int fini);
static int detach_out (qse_tio_t* tio, int fini);
qse_tio_t* qse_tio_open (qse_mmgr_t* mmgr, qse_size_t xtnsize, int flags)
{
qse_tio_t* tio;
tio = QSE_MMGR_ALLOC (mmgr, QSE_SIZEOF(qse_tio_t) + xtnsize);
if (tio)
{
if (qse_tio_init (tio, mmgr, flags) <= -1)
{
QSE_MMGR_FREE (mmgr, tio);
return QSE_NULL;
}
else QSE_MEMSET (QSE_XTN(tio), 0, xtnsize);
}
return tio;
}
int qse_tio_close (qse_tio_t* tio)
{
int n = qse_tio_fini (tio);
QSE_MMGR_FREE (tio->mmgr, tio);
return n;
}
int qse_tio_init (qse_tio_t* tio, qse_mmgr_t* mmgr, int flags)
{
QSE_MEMSET (tio, 0, QSE_SIZEOF(*tio));
tio->mmgr = mmgr;
tio->cmgr = qse_getdflcmgr();
tio->flags = flags;
/*
tio->input_func = QSE_NULL;
tio->input_arg = QSE_NULL;
tio->output_func = QSE_NULL;
tio->output_arg = QSE_NULL;
tio->status = 0;
tio->inbuf_cur = 0;
tio->inbuf_len = 0;
tio->outbuf_len = 0;
*/
tio->errnum = QSE_TIO_ENOERR;
return 0;
}
int qse_tio_fini (qse_tio_t* tio)
{
int ret = 0;
qse_tio_flush (tio); /* don't care about the result */
if (detach_in (tio, 1) <= -1) ret = -1;
if (detach_out (tio, 1) <= -1) ret = -1;
return ret;
}
qse_mmgr_t* qse_tio_getmmgr (qse_tio_t* tio)
{
return tio->mmgr;
}
void* qse_tio_getxtn (qse_tio_t* tio)
{
return QSE_XTN (tio);
}
qse_tio_errnum_t qse_tio_geterrnum (const qse_tio_t* tio)
{
return tio->errnum;
}
void qse_tio_seterrnum (qse_tio_t* tio, qse_tio_errnum_t errnum)
{
tio->errnum = errnum;
}
qse_cmgr_t* qse_tio_getcmgr (qse_tio_t* tio)
{
return tio->cmgr;
}
void qse_tio_setcmgr (qse_tio_t* tio, qse_cmgr_t* cmgr)
{
tio->cmgr = cmgr;
}
int qse_tio_attachin (
qse_tio_t* tio, qse_tio_io_impl_t input,
qse_mchar_t* bufptr, qse_size_t bufcapa)
{
qse_mchar_t* xbufptr;
if (input == QSE_NULL || bufcapa < QSE_TIO_MININBUFCAPA)
{
tio->errnum = QSE_TIO_EINVAL;
return -1;
}
if (qse_tio_detachin(tio) <= -1) return -1;
QSE_ASSERT (tio->in.fun == QSE_NULL);
xbufptr = bufptr;
if (xbufptr == QSE_NULL)
{
xbufptr = QSE_MMGR_ALLOC (
tio->mmgr, QSE_SIZEOF(qse_mchar_t) * bufcapa);
if (xbufptr == QSE_NULL)
{
tio->errnum = QSE_TIO_ENOMEM;
return -1;
}
}
tio->errnum = QSE_TIO_ENOERR;
if (input (tio, QSE_TIO_OPEN, QSE_NULL, 0) <= -1)
{
if (tio->errnum == QSE_TIO_ENOERR) tio->errnum = QSE_TIO_EOTHER;
if (xbufptr != bufptr) QSE_MMGR_FREE (tio->mmgr, xbufptr);
return -1;
}
/* if i defined tio->io[2] instead of tio->in and tio-out,
* i would be able to shorten code amount. but fields to initialize
* are not symmetric between input and output.
* so it's just a bit clumsy that i repeat almost the same code
* in qse_tio_attachout().
*/
tio->in.fun = input;
tio->in.buf.ptr = xbufptr;
tio->in.buf.capa = bufcapa;
tio->status &= ~(STATUS_INPUT_ILLSEQ | STATUS_INPUT_EOF);
tio->inbuf_cur = 0;
tio->inbuf_len = 0;
if (xbufptr != bufptr) tio->status |= STATUS_INPUT_DYNBUF;
return 0;
}
static int detach_in (qse_tio_t* tio, int fini)
{
int ret = 0;
if (tio->in.fun)
{
tio->errnum = QSE_TIO_ENOERR;
if (tio->in.fun (tio, QSE_TIO_CLOSE, QSE_NULL, 0) <= -1)
{
if (tio->errnum == QSE_TIO_ENOERR) tio->errnum = QSE_TIO_EOTHER;
/* returning with an error here allows you to retry detaching */
if (!fini) return -1;
/* otherwise, you can't retry since the input handler information
* is reset below */
ret = -1;
}
if (tio->status & STATUS_INPUT_DYNBUF)
{
QSE_MMGR_FREE (tio->mmgr, tio->in.buf.ptr);
tio->status &= ~STATUS_INPUT_DYNBUF;
}
tio->in.fun = QSE_NULL;
tio->in.buf.ptr = QSE_NULL;
tio->in.buf.capa = 0;
}
return ret;
}
int qse_tio_detachin (qse_tio_t* tio)
{
return detach_in (tio, 0);
}
int qse_tio_attachout (
qse_tio_t* tio, qse_tio_io_impl_t output,
qse_mchar_t* bufptr, qse_size_t bufcapa)
{
qse_mchar_t* xbufptr;
if (output == QSE_NULL || bufcapa < QSE_TIO_MINOUTBUFCAPA)
{
tio->errnum = QSE_TIO_EINVAL;
return -1;
}
if (qse_tio_detachout(tio) == -1) return -1;
QSE_ASSERT (tio->out.fun == QSE_NULL);
xbufptr = bufptr;
if (xbufptr == QSE_NULL)
{
xbufptr = QSE_MMGR_ALLOC (
tio->mmgr, QSE_SIZEOF(qse_mchar_t) * bufcapa);
if (xbufptr == QSE_NULL)
{
tio->errnum = QSE_TIO_ENOMEM;
return -1;
}
}
tio->errnum = QSE_TIO_ENOERR;
if (output (tio, QSE_TIO_OPEN, QSE_NULL, 0) <= -1)
{
if (tio->errnum == QSE_TIO_ENOERR) tio->errnum = QSE_TIO_EOTHER;
if (xbufptr != bufptr) QSE_MMGR_FREE (tio->mmgr, xbufptr);
return -1;
}
tio->out.fun = output;
tio->out.buf.ptr = xbufptr;
tio->out.buf.capa = bufcapa;
tio->outbuf_len = 0;
if (xbufptr != bufptr) tio->status |= STATUS_OUTPUT_DYNBUF;
return 0;
}
static int detach_out (qse_tio_t* tio, int fini)
{
int ret = 0;
if (tio->out.fun)
{
qse_tio_flush (tio); /* don't care about the result */
tio->errnum = QSE_TIO_ENOERR;
if (tio->out.fun (tio, QSE_TIO_CLOSE, QSE_NULL, 0) <= -1)
{
if (tio->errnum == QSE_TIO_ENOERR) tio->errnum = QSE_TIO_EOTHER;
/* returning with an error here allows you to retry detaching */
if (!fini) return -1;
/* otherwise, you can't retry since the input handler information
* is reset below */
ret = -1;
}
if (tio->status & STATUS_OUTPUT_DYNBUF)
{
QSE_MMGR_FREE (tio->mmgr, tio->out.buf.ptr);
tio->status &= ~STATUS_OUTPUT_DYNBUF;
}
tio->out.fun = QSE_NULL;
tio->out.buf.ptr = QSE_NULL;
tio->out.buf.capa = 0;
}
return ret;
}
int qse_tio_detachout (qse_tio_t* tio)
{
return detach_out (tio, 0);
}
qse_ssize_t qse_tio_flush (qse_tio_t* tio)
{
qse_size_t left, count;
qse_ssize_t n;
qse_mchar_t* cur;
if (tio->out.fun == QSE_NULL)
{
tio->errnum = QSE_TIO_ENOUTF;
return (qse_ssize_t)-1;
}
left = tio->outbuf_len;
cur = tio->out.buf.ptr;
while (left > 0)
{
tio->errnum = QSE_TIO_ENOERR;
n = tio->out.fun (tio, QSE_TIO_DATA, cur, left);
if (n <= -1)
{
if (tio->errnum == QSE_TIO_ENOERR) tio->errnum = QSE_TIO_EOTHER;
if (cur != tio->out.buf.ptr)
{
QSE_MEMCPY (tio->out.buf.ptr, cur, left);
tio->outbuf_len = left;
}
return -1;
}
if (n == 0)
{
if (cur != tio->out.buf.ptr)
QSE_MEMCPY (tio->out.buf.ptr, cur, left);
break;
}
left -= n;
cur += n;
}
count = tio->outbuf_len - left;
tio->outbuf_len = left;
return (qse_ssize_t)count;
}
void qse_tio_drain (qse_tio_t* tio)
{
tio->status &= ~(STATUS_INPUT_ILLSEQ | STATUS_INPUT_EOF);
tio->inbuf_cur = 0;
tio->inbuf_len = 0;
tio->outbuf_len = 0;
tio->errnum = QSE_TIO_ENOERR;
}
/* ------------------------------------------------------------- */
qse_ssize_t qse_tio_readmbs (qse_tio_t* tio, qse_mchar_t* buf, qse_size_t size)
{
qse_size_t nread;
qse_ssize_t n;
/*QSE_ASSERT (tio->in.fun != QSE_NULL);*/
if (tio->in.fun == QSE_NULL)
{
tio->errnum = QSE_TIO_ENINPF;
return -1;
}
/* note that this function doesn't check if
* tio->status is set with STATUS_INPUT_ILLSEQ
* since this function can simply return the next
* available byte. */
if (size > QSE_TYPE_MAX(qse_ssize_t)) size = QSE_TYPE_MAX(qse_ssize_t);
nread = 0;
while (nread < size)
{
if (tio->inbuf_cur >= tio->inbuf_len)
{
tio->errnum = QSE_TIO_ENOERR;
n = tio->in.fun (
tio, QSE_TIO_DATA,
tio->in.buf.ptr, tio->in.buf.capa);
if (n == 0) break;
if (n <= -1)
{
if (tio->errnum == QSE_TIO_ENOERR) tio->errnum = QSE_TIO_EOTHER;
return -1;
}
tio->inbuf_cur = 0;
tio->inbuf_len = (qse_size_t)n;
}
do
{
buf[nread] = tio->in.buf.ptr[tio->inbuf_cur++];
/* TODO: support a different line terminator */
if (buf[nread++] == QSE_MT('\n')) goto done;
}
while (tio->inbuf_cur < tio->inbuf_len && nread < size);
}
done:
return nread;
}
static QSE_INLINE qse_ssize_t tio_read_widechars (
qse_tio_t* tio, qse_wchar_t* buf, qse_size_t bufsize)
{
qse_size_t mlen, wlen;
qse_ssize_t n;
int x;
if (tio->inbuf_cur >= tio->inbuf_len)
{
tio->inbuf_cur = 0;
tio->inbuf_len = 0;
getc_conv:
if (tio->status & STATUS_INPUT_EOF) n = 0;
else
{
tio->errnum = QSE_TIO_ENOERR;
n = tio->in.fun (
tio, QSE_TIO_DATA,
&tio->in.buf.ptr[tio->inbuf_len],
tio->in.buf.capa - tio->inbuf_len);
}
if (n == 0)
{
tio->status |= STATUS_INPUT_EOF;
if (tio->inbuf_cur < tio->inbuf_len)
{
/* no more input from the underlying input handler.
* but some incomplete bytes in the buffer. */
if (tio->flags & QSE_TIO_IGNOREMBWCERR)
{
/* tread them as illegal sequence */
goto ignore_illseq;
}
else
{
tio->errnum = QSE_TIO_EICSEQ;
return -1;
}
}
return 0;
}
if (n <= -1)
{
if (tio->errnum == QSE_TIO_ENOERR) tio->errnum = QSE_TIO_EOTHER;
return -1;
}
tio->inbuf_len += n;
}
mlen = tio->inbuf_len - tio->inbuf_cur;
wlen = bufsize;
x = qse_mbsntowcsnuptowithcmgr (
&tio->in.buf.ptr[tio->inbuf_cur],
&mlen, buf, &wlen, QSE_WT('\n'), tio->cmgr);
tio->inbuf_cur += mlen;
if (x == -3)
{
/* incomplete sequence */
if (wlen <= 0)
{
/* not even a single character was handled.
* shift bytes in the buffer to the head. */
QSE_ASSERT (mlen <= 0);
tio->inbuf_len = tio->inbuf_len - tio->inbuf_cur;
QSE_MEMCPY (&tio->in.buf.ptr[0],
&tio->in.buf.ptr[tio->inbuf_cur],
tio->inbuf_len * QSE_SIZEOF(tio->in.buf.ptr[0]));
tio->inbuf_cur = 0;
goto getc_conv; /* and read more */
}
/* get going if some characters are handled */
}
else if (x == -2)
{
/* buffer not large enough */
QSE_ASSERT (wlen > 0);
/* the wide-character buffer is not just large enough to
* hold the entire conversion result. lets's go on so long as
* 1 wide-character is produced though it may be inefficient.
*/
}
else if (x <= -1)
{
/* illegal sequence */
if (tio->flags & QSE_TIO_IGNOREMBWCERR)
{
ignore_illseq:
tio->inbuf_cur++; /* skip one byte */
buf[wlen++] = QSE_WT('?');
}
else if (wlen <= 0)
{
tio->errnum = QSE_TIO_EILSEQ;
return -1;
}
else
{
/* some characters are already handled.
* mark that an illegal sequence encountered
* and carry on. */
tio->status |= STATUS_INPUT_ILLSEQ;
}
}
return wlen;
}
qse_ssize_t qse_tio_readwcs (qse_tio_t* tio, qse_wchar_t* buf, qse_size_t size)
{
qse_size_t nread = 0;
qse_ssize_t n;
/*QSE_ASSERT (tio->in.fun != QSE_NULL);*/
if (tio->in.fun == QSE_NULL)
{
tio->errnum = QSE_TIO_ENINPF;
return -1;
}
if (size > QSE_TYPE_MAX(qse_ssize_t)) size = QSE_TYPE_MAX(qse_ssize_t);
while (nread < size)
{
if (tio->status & STATUS_INPUT_ILLSEQ)
{
tio->status &= ~STATUS_INPUT_ILLSEQ;
tio->errnum = QSE_TIO_EILSEQ;
return -1;
}
n = tio_read_widechars (tio, &buf[nread], size - nread);
if (n == 0) break;
if (n <= -1) return -1;
nread += n;
if (buf[nread-1] == QSE_WT('\n')) break;
}
return nread;
}
/* ------------------------------------------------------------- */
qse_ssize_t qse_tio_writembs (
qse_tio_t* tio, const qse_mchar_t* mptr, qse_size_t mlen)
{
if (tio->outbuf_len >= tio->out.buf.capa)
{
/* maybe, previous flush operation has failed a few
* times previously. so the buffer is full.
*/
tio->errnum = QSE_TIO_ENOSPC;
return -1;
}
if (mlen == (qse_size_t)-1)
{
qse_size_t pos = 0;
if (tio->flags & QSE_TIO_NOAUTOFLUSH)
{
while (mptr[pos] != QSE_MT('\0'))
{
tio->out.buf.ptr[tio->outbuf_len++] = mptr[pos++];
if (tio->outbuf_len >= tio->out.buf.capa &&
qse_tio_flush (tio) <= -1) return -1;
if (pos >= QSE_TYPE_MAX(qse_ssize_t)) break;
}
}
else
{
int nl = 0;
while (mptr[pos] != QSE_MT('\0'))
{
tio->out.buf.ptr[tio->outbuf_len++] = mptr[pos];
if (tio->outbuf_len >= tio->out.buf.capa)
{
if (qse_tio_flush (tio) <= -1) return -1;
nl = 0;
}
else if (mptr[pos] == QSE_T('\n')) nl = 1;
/* TODO: different line terminator */
if (++pos >= QSE_TYPE_MAX(qse_ssize_t)) break;
}
if (nl && qse_tio_flush(tio) <= -1) return -1;
}
return pos;
}
else
{
const qse_mchar_t* xptr, * xend;
qse_size_t capa;
int nl = 0;
/* adjust mlen for the type difference between the parameter
* and the return value */
if (mlen > QSE_TYPE_MAX(qse_ssize_t)) mlen = QSE_TYPE_MAX(qse_ssize_t);
xptr = mptr;
/* handle the parts that can't fit into the internal buffer */
while (mlen >= (capa = tio->out.buf.capa - tio->outbuf_len))
{
for (xend = xptr + capa; xptr < xend; xptr++)
tio->out.buf.ptr[tio->outbuf_len++] = *xptr;
if (qse_tio_flush (tio) <= -1) return -1;
mlen -= capa;
}
if (tio->flags & QSE_TIO_NOAUTOFLUSH)
{
/* handle the last part that can fit into the internal buffer */
for (xend = xptr + mlen; xptr < xend; xptr++)
tio->out.buf.ptr[tio->outbuf_len++] = *xptr;
}
else
{
/* handle the last part that can fit into the internal buffer */
for (xend = xptr + mlen; xptr < xend; xptr++)
{
/* TODO: support different line terminating characeter */
if (*xptr == QSE_MT('\n'))
{
nl = 1;
break;
}
tio->out.buf.ptr[tio->outbuf_len++] = *xptr;
}
/* continue copying without checking for nl */
while (xptr < xend) tio->out.buf.ptr[tio->outbuf_len++] = *xptr++;
}
/* if the last part contains a new line, flush the internal
* buffer. note that this flushes characters after nl also.*/
if (nl && qse_tio_flush (tio) <= -1) return -1;
/* returns the number multi-byte characters handled */
return xptr - mptr;
}
}
qse_ssize_t qse_tio_writewcs (
qse_tio_t* tio, const qse_wchar_t* wptr, qse_size_t wlen)
{
qse_size_t capa, wcnt, mcnt, xwlen;
int n, nl = 0;
if (tio->outbuf_len >= tio->out.buf.capa)
{
/* maybe, previous flush operation has failed a few
* times previously. so the buffer is full. */
tio->errnum = QSE_TIO_ENOSPC;
return -1;
}
if (wlen == (qse_size_t)-1) wlen = qse_wcslen(wptr);
if (wlen > QSE_TYPE_MAX(qse_ssize_t)) wlen = QSE_TYPE_MAX(qse_ssize_t);
xwlen = wlen;
while (xwlen > 0)
{
capa = tio->out.buf.capa - tio->outbuf_len;
wcnt = xwlen; mcnt = capa;
n = qse_wcsntombsnwithcmgr (
wptr, &wcnt, &tio->out.buf.ptr[tio->outbuf_len], &mcnt, tio->cmgr);
tio->outbuf_len += mcnt;
if (n == -2)
{
/* the buffer is not large enough to
* convert more. so flush now and continue.
* note that the buffer may not be full though
* it is not large enough in this case */
if (qse_tio_flush (tio) <= -1) return -1;
nl = 0;
}
else
{
if (tio->outbuf_len >= tio->out.buf.capa)
{
/* flush the full buffer regardless of conversion
* result. */
if (qse_tio_flush (tio) <= -1) return -1;
nl = 0;
}
if (n <= -1)
{
/* an invalid wide-character is encountered. */
if (tio->flags & QSE_TIO_IGNOREMBWCERR)
{
/* insert a question mark for an illegal
* character. */
QSE_ASSERT (tio->outbuf_len < tio->out.buf.capa);
tio->out.buf.ptr[tio->outbuf_len++] = QSE_MT('?');
wcnt++; /* skip this illegal character */
/* don't need to increment mcnt since
* it's not used below */
}
else
{
tio->errnum = QSE_TIO_EILCHR;
return -1;
}
}
else
{
if (!(tio->flags & QSE_TIO_NOAUTOFLUSH) && !nl)
{
/* checking for a newline this way looks damn ugly.
* TODO: how can i do this more elegantly? */
qse_size_t i = wcnt;
while (i > 0)
{
/* scan backward assuming a line terminator
* is typically at the back */
if (wptr[--i] == QSE_WT('\n'))
{
/* TOOD: differetn line terminator */
nl = 1;
break;
}
}
}
}
}
wptr += wcnt; xwlen -= wcnt;
}
if (nl && qse_tio_flush (tio) <= -1) return -1;
return wlen;
}