merged sys and io to si
This commit is contained in:
		
							
								
								
									
										40
									
								
								qse/lib/si/Makefile.am
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								qse/lib/si/Makefile.am
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										830
									
								
								qse/lib/si/Makefile.in
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										71
									
								
								qse/lib/si/Socket.cpp
									
									
									
									
									
										Normal 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) | ||||
| ///////////////////////////////// | ||||
							
								
								
									
										220
									
								
								qse/lib/si/SocketAddress.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										220
									
								
								qse/lib/si/SocketAddress.cpp
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										852
									
								
								qse/lib/si/aio-pro.c
									
									
									
									
									
										Normal 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, ¶m) <= -1) goto oops; | ||||
|  | ||||
| /* TODO: more advanced fork and exec .. */ | ||||
| 	pid = standard_fork_and_exec (rdev->aio, pfds, info->flags, ¶m); | ||||
| 	if (pid <= -1)  | ||||
| 	{ | ||||
| 		free_param (rdev->aio, ¶m); | ||||
| 		goto oops; | ||||
| 	} | ||||
|  | ||||
| 	free_param (rdev->aio, ¶m); | ||||
| 	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, ¶m); | ||||
| 	} | ||||
|  | ||||
| 	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
									
								
							
							
						
						
									
										115
									
								
								qse/lib/si/aio-prv.h
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										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
									
								
							
							
						
						
									
										234
									
								
								qse/lib/si/aio-tmr.c
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										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
									
								
							
							
						
						
									
										381
									
								
								qse/lib/si/cnd.c
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										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
									
								
							
							
						
						
									
										162
									
								
								qse/lib/si/intr.c
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										257
									
								
								qse/lib/si/mtx.c
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										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
									
								
							
							
						
						
									
										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
									
								
							
							
						
						
									
										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
									
								
							
							
						
						
									
										251
									
								
								qse/lib/si/rwl.c
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										982
									
								
								qse/lib/si/sio.c
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										644
									
								
								qse/lib/si/task.c
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										84
									
								
								qse/lib/si/thr-prv.h
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										430
									
								
								qse/lib/si/thr.c
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										759
									
								
								qse/lib/si/tio.c
									
									
									
									
									
										Normal 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; | ||||
| } | ||||
		Reference in New Issue
	
	Block a user