diff options
Diffstat (limited to 'libs/ode-0.16.1/ou/src')
-rw-r--r-- | libs/ode-0.16.1/ou/src/ou/Makefile.am | 13 | ||||
-rw-r--r-- | libs/ode-0.16.1/ou/src/ou/Makefile.in | 598 | ||||
-rw-r--r-- | libs/ode-0.16.1/ou/src/ou/atomic.cpp | 445 | ||||
-rw-r--r-- | libs/ode-0.16.1/ou/src/ou/customization.cpp | 64 | ||||
-rw-r--r-- | libs/ode-0.16.1/ou/src/ou/malloc.cpp | 106 | ||||
-rw-r--r-- | libs/ode-0.16.1/ou/src/ou/threadlocalstorage.cpp | 1336 |
6 files changed, 2562 insertions, 0 deletions
diff --git a/libs/ode-0.16.1/ou/src/ou/Makefile.am b/libs/ode-0.16.1/ou/src/ou/Makefile.am new file mode 100644 index 0000000..12a40cd --- /dev/null +++ b/libs/ode-0.16.1/ou/src/ou/Makefile.am @@ -0,0 +1,13 @@ +AM_CPPFLAGS = -I$(top_srcdir)/include + +AM_CXXFLAGS = -fno-exceptions -fno-rtti +AM_LDFLAGS = -fno-exceptions -fno-rtti + +noinst_LTLIBRARIES = libou.la + +libou_la_SOURCES = atomic.cpp \ + customization.cpp \ + malloc.cpp \ + threadlocalstorage.cpp + + diff --git a/libs/ode-0.16.1/ou/src/ou/Makefile.in b/libs/ode-0.16.1/ou/src/ou/Makefile.in new file mode 100644 index 0000000..b2d755b --- /dev/null +++ b/libs/ode-0.16.1/ou/src/ou/Makefile.in @@ -0,0 +1,598 @@ +# Makefile.in generated by automake 1.15 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2014 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 = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +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@ +subdir = src/ou +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LTLIBRARIES = $(noinst_LTLIBRARIES) +libou_la_LIBADD = +am_libou_la_OBJECTS = atomic.lo customization.lo malloc.lo \ + threadlocalstorage.lo +libou_la_OBJECTS = $(am_libou_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 = +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 = -I.@am__isrc@ +depcomp = $(SHELL) $(top_srcdir)/../depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +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 = $(libou_la_SOURCES) +DIST_SOURCES = $(libou_la_SOURCES) +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 +am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/../depcomp +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +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_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +OU_FEATURE_SET = @OU_FEATURE_SET@ +OU_NAMESPACE = @OU_NAMESPACE@ +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@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +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@ +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@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +runstatedir = @runstatedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +AM_CPPFLAGS = -I$(top_srcdir)/include +AM_CXXFLAGS = -fno-exceptions -fno-rtti +AM_LDFLAGS = -fno-exceptions -fno-rtti +noinst_LTLIBRARIES = libou.la +libou_la_SOURCES = atomic.cpp \ + customization.cpp \ + malloc.cpp \ + threadlocalstorage.cpp + +all: all-am + +.SUFFIXES: +.SUFFIXES: .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 src/ou/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/ou/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): + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_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}; \ + } + +libou.la: $(libou_la_OBJECTS) $(libou_la_DEPENDENCIES) $(EXTRA_libou_la_DEPENDENCIES) + $(AM_V_CXXLD)$(CXXLINK) $(libou_la_OBJECTS) $(libou_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/atomic.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/customization.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/malloc.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/threadlocalstorage.Plo@am__quote@ + +.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: +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-libtool clean-noinstLTLIBRARIES \ + 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-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: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-noinstLTLIBRARIES 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-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 + +.PRECIOUS: Makefile + + +# 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: diff --git a/libs/ode-0.16.1/ou/src/ou/atomic.cpp b/libs/ode-0.16.1/ou/src/ou/atomic.cpp new file mode 100644 index 0000000..609cf41 --- /dev/null +++ b/libs/ode-0.16.1/ou/src/ou/atomic.cpp @@ -0,0 +1,445 @@ +/************************************************************************* + * * + * ODER's Utilities Library. Copyright (C) 2008-2019 Oleh Derevenko. * + * All rights reserved. e-mail: odar@eleks.com (change all "a" to "e") * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 3 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE-LESSER.TXT. Since LGPL is the extension of GPL * + * the text of GNU General Public License is also provided for * + * your information in file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * (3) The zlib/libpng license that is included with this library in * + * the file LICENSE-ZLIB.TXT * + * * + * This library is distributed WITHOUT ANY WARRANTY, including implied * + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + * See the files LICENSE.TXT and LICENSE-LESSER.TXT or LICENSE-BSD.TXT * + * or LICENSE-ZLIB.TXT for more details. * + * * + *************************************************************************/ + +#include <ou/features.h> + + +#if _OU_FEATURE_SET >= _OU_FEATURE_SET_ATOMICS + +#include <ou/atomic.h> +#include <ou/assert.h> +#include <ou/namespace.h> + + +BEGIN_NAMESPACE_OU(); + + +#if !defined(__OU_ATOMIC_PTR_FUNCTIONS_DEFINED) + +////////////////////////////////////////////////////////////////////////// +// Implementation via mutex locks + +#if !defined(__OU_ATOMIC_INITIALIZATION_FUNCTIONS_REQUIRED) + +#error Internal error (Atomic-via-mutex implementations can not appear without initialization) + + +#endif // #if !defined(__OU_ATOMIC_INITIALIZATION_FUNCTIONS_DEFINED) + + +END_NAMESPACE_OU(); + + +#include <pthread.h> +#include <errno.h> + +#if !defined(EOK) + +#define EOK 0 + + +#endif + + +BEGIN_NAMESPACE_OU(); + + +static unsigned int g_uiAtomicAPIInitializationCount = 0; + + +#define _OU_ATOMIC_MUTEX_COUNT 8 +#define _OU_ATOMIC_MUTES_INDEX_SHIFT 3 // Shift by 3 bits as 8 bytes is a common memory alignment +#define _OU_ATOMIC_MUTEX_INDEX_MASK (_OU_ATOMIC_MUTEX_COUNT - 1) + + +// Mutexes array is used to distribute load over multiple mutexes +static pthread_mutex_t g_apmAtomicMutexes[_OU_ATOMIC_MUTEX_COUNT]; + + +static inline unsigned int DeriveAtomicMutexIndex(void *pv_Destination) +{ + return ((unsigned int)(size_t)pv_Destination >> _OU_ATOMIC_MUTES_INDEX_SHIFT) & _OU_ATOMIC_MUTEX_INDEX_MASK; +} + + +////////////////////////////////////////////////////////////////////////// +// Atomic ord32 functions implementation + +#if !defined(__OU_ATOMIC_ORD32_FUNCTIONS_DEFINED) + +/*extern*/ atomicord32 AtomicIncrement(volatile atomicord32 *paoDestination) +{ + const unsigned int uiMutexIndex = DeriveAtomicMutexIndex((void *)paoDestination); + pthread_mutex_t *ptmMutexToBeUsed = g_apmAtomicMutexes + uiMutexIndex; + + int iLockResult = pthread_mutex_lock(ptmMutexToBeUsed); + OU_CHECK(iLockResult == EOK); + + const atomicord32 aoNewValue = ++(*paoDestination); + + int iUnlockResult = pthread_mutex_unlock(ptmMutexToBeUsed); + OU_CHECK(iUnlockResult == EOK); + + atomicord32 aoResult = aoNewValue; + return aoResult; +} + +/*extern*/ atomicord32 AtomicDecrement(volatile atomicord32 *paoDestination) +{ + const unsigned int uiMutexIndex = DeriveAtomicMutexIndex((void *)paoDestination); + pthread_mutex_t *ptmMutexToBeUsed = g_apmAtomicMutexes + uiMutexIndex; + + int iLockResult = pthread_mutex_lock(ptmMutexToBeUsed); + OU_CHECK(iLockResult == EOK); + + const atomicord32 aoNewValue = --(*paoDestination); + + int iUnlockResult = pthread_mutex_unlock(ptmMutexToBeUsed); + OU_CHECK(iUnlockResult == EOK); + + atomicord32 aoResult = aoNewValue; + return aoResult; +} + + +/*extern*/ atomicord32 AtomicExchange(volatile atomicord32 *paoDestination, atomicord32 aoExchange) +{ + const unsigned int uiMutexIndex = DeriveAtomicMutexIndex((void *)paoDestination); + pthread_mutex_t *ptmMutexToBeUsed = g_apmAtomicMutexes + uiMutexIndex; + + int iLockResult = pthread_mutex_lock(ptmMutexToBeUsed); + OU_CHECK(iLockResult == EOK); + + const atomicord32 aoOldValue = *paoDestination; + + *paoDestination = aoExchange; + + int iUnlockResult = pthread_mutex_unlock(ptmMutexToBeUsed); + OU_CHECK(iUnlockResult == EOK); + + atomicord32 aoResult = aoOldValue; + return aoResult; +} + +/*extern*/ atomicord32 AtomicExchangeAdd(volatile atomicord32 *paoDestination, atomicord32 aoAddend) +{ + const unsigned int uiMutexIndex = DeriveAtomicMutexIndex((void *)paoDestination); + pthread_mutex_t *ptmMutexToBeUsed = g_apmAtomicMutexes + uiMutexIndex; + + int iLockResult = pthread_mutex_lock(ptmMutexToBeUsed); + OU_CHECK(iLockResult == EOK); + + const atomicord32 aoOldValue = *paoDestination; + + *paoDestination += aoAddend; + + int iUnlockResult = pthread_mutex_unlock(ptmMutexToBeUsed); + OU_CHECK(iUnlockResult == EOK); + + atomicord32 aoResult = aoOldValue; + return aoResult; +} + +/*extern*/ bool AtomicCompareExchange(volatile atomicord32 *paoDestination, atomicord32 aoComparand, atomicord32 aoExchange) +{ + bool bResult = false; + + const unsigned int uiMutexIndex = DeriveAtomicMutexIndex((void *)paoDestination); + pthread_mutex_t *ptmMutexToBeUsed = g_apmAtomicMutexes + uiMutexIndex; + + int iLockResult = pthread_mutex_lock(ptmMutexToBeUsed); + OU_CHECK(iLockResult == EOK); + + const atomicord32 aoOldValue = *paoDestination; + + if (aoOldValue == aoComparand) + { + *paoDestination = aoExchange; + + bResult = true; + } + + int iUnlockResult = pthread_mutex_unlock(ptmMutexToBeUsed); + OU_CHECK(iUnlockResult == EOK); + + return bResult; +} + + +/*extern*/ atomicord32 AtomicAnd(volatile atomicord32 *paoDestination, atomicord32 aoBitMask) +{ + const unsigned int uiMutexIndex = DeriveAtomicMutexIndex((void *)paoDestination); + pthread_mutex_t *ptmMutexToBeUsed = g_apmAtomicMutexes + uiMutexIndex; + + int iLockResult = pthread_mutex_lock(ptmMutexToBeUsed); + OU_CHECK(iLockResult == EOK); + + const atomicord32 aoOldValue = *paoDestination; + + *paoDestination &= aoBitMask; + + int iUnlockResult = pthread_mutex_unlock(ptmMutexToBeUsed); + OU_CHECK(iUnlockResult == EOK); + + atomicord32 aoResult = aoOldValue; + return aoResult; +} + +/*extern*/ atomicord32 AtomicOr(volatile atomicord32 *paoDestination, atomicord32 aoBitMask) +{ + const unsigned int uiMutexIndex = DeriveAtomicMutexIndex((void *)paoDestination); + pthread_mutex_t *ptmMutexToBeUsed = g_apmAtomicMutexes + uiMutexIndex; + + int iLockResult = pthread_mutex_lock(ptmMutexToBeUsed); + OU_CHECK(iLockResult == EOK); + + const atomicord32 aoOldValue = *paoDestination; + + *paoDestination |= aoBitMask; + + int iUnlockResult = pthread_mutex_unlock(ptmMutexToBeUsed); + OU_CHECK(iUnlockResult == EOK); + + atomicord32 aoResult = aoOldValue; + return aoResult; +} + +/*extern*/ atomicord32 AtomicXor(volatile atomicord32 *paoDestination, atomicord32 aoBitMask) +{ + const unsigned int uiMutexIndex = DeriveAtomicMutexIndex((void *)paoDestination); + pthread_mutex_t *ptmMutexToBeUsed = g_apmAtomicMutexes + uiMutexIndex; + + int iLockResult = pthread_mutex_lock(ptmMutexToBeUsed); + OU_CHECK(iLockResult == EOK); + + const atomicord32 aoOldValue = *paoDestination; + + *paoDestination ^= aoBitMask; + + int iUnlockResult = pthread_mutex_unlock(ptmMutexToBeUsed); + OU_CHECK(iUnlockResult == EOK); + + atomicord32 aoResult = aoOldValue; + return aoResult; +} + + +#endif // #if !defined(__OU_ATOMIC_ORD32_FUNCTIONS_DEFINED) + + +////////////////////////////////////////////////////////////////////////// +// Atomic pointer functions implementation + +/*extern*/ atomicptr AtomicExchangePointer(volatile atomicptr *papDestination, atomicptr apExchange) +{ + const unsigned int uiMutexIndex = DeriveAtomicMutexIndex((void *)papDestination); + pthread_mutex_t *ptmMutexToBeUsed = g_apmAtomicMutexes + uiMutexIndex; + + int iLockResult = pthread_mutex_lock(ptmMutexToBeUsed); + OU_CHECK(iLockResult == EOK); + + const atomicptr apOldValue = *papDestination; + + *papDestination = apExchange; + + int iUnlockResult = pthread_mutex_unlock(ptmMutexToBeUsed); + OU_CHECK(iUnlockResult == EOK); + + atomicptr apResult = apOldValue; + return apResult; +} + +/*extern*/ bool AtomicCompareExchangePointer(volatile atomicptr *papDestination, atomicptr apComparand, atomicptr apExchange) +{ + bool bResult = false; + + const unsigned int uiMutexIndex = DeriveAtomicMutexIndex((void *)papDestination); + pthread_mutex_t *ptmMutexToBeUsed = g_apmAtomicMutexes + uiMutexIndex; + + int iLockResult = pthread_mutex_lock(ptmMutexToBeUsed); + OU_CHECK(iLockResult == EOK); + + const atomicptr apOldValue = *papDestination; + + if (apOldValue == apComparand) + { + *papDestination = apExchange; + + bResult = true; + } + + int iUnlockResult = pthread_mutex_unlock(ptmMutexToBeUsed); + OU_CHECK(iUnlockResult == EOK); + + return bResult; +} + + +////////////////////////////////////////////////////////////////////////// +// Atomic initialization functions implementation + +static void FreeAtomicMutexes(unsigned int nLastMutexIndex=0) +{ + const unsigned int nMutexCount = nLastMutexIndex == 0 ? _OU_ATOMIC_MUTEX_COUNT : nLastMutexIndex; + + for (unsigned int nMutexIndex = 0; nMutexIndex != nMutexCount; ++nMutexIndex) + { + int iMutexDestroyResult = pthread_mutex_destroy(g_apmAtomicMutexes + nMutexIndex); + OU_VERIFY(iMutexDestroyResult == EOK); // Ignore the error + } +} + +static bool CreateAtomicMutexesWithAttributes(pthread_mutexattr_t *pmaMutexAttributes) +{ + const unsigned int nMutexCount = _OU_ATOMIC_MUTEX_COUNT; + + unsigned int nMutexIndex = 0; + + for (; nMutexIndex != nMutexCount; ++nMutexIndex) + { + int iMutexInitResult = pthread_mutex_init(g_apmAtomicMutexes + nMutexIndex, pmaMutexAttributes); + + if (iMutexInitResult != EOK) + { + if (nMutexIndex != 0) + { + FreeAtomicMutexes(nMutexIndex); + } + + break; + } + } + + bool bResult = nMutexIndex == nMutexCount; + return bResult; +} + +static bool CreateAtomicMutexes() +{ + bool bResult = false; + + pthread_mutexattr_t maMutexAttributes; + + int iAttrInitResult = pthread_mutexattr_init(&maMutexAttributes); + + if (iAttrInitResult == EOK) + { + bResult = CreateAtomicMutexesWithAttributes(&maMutexAttributes); + + int iAttrDestroyResult = pthread_mutexattr_destroy(&maMutexAttributes); + OU_VERIFY(iAttrDestroyResult == EOK); // Ignore error + } + + return bResult; +} + + +static bool InitializeAtomicAPIValidated() +{ + bool bResult = false; + + do + { + if (!CreateAtomicMutexes()) + { + break; + } + + bResult = true; + } + while (false); + + return bResult; +} + +static void FinalizeAtomicAPIValidated() +{ + FreeAtomicMutexes(); +} + + +/*extern*/ bool InitializeAtomicAPI() +{ + OU_ASSERT(g_uiAtomicAPIInitializationCount != 0U - 1U); + + bool bResult = false; + + do + { + if (g_uiAtomicAPIInitializationCount == 0) // Initialization/finalization must be called from main thread + { + if (!InitializeAtomicAPIValidated()) + { + break; + } + } + + ++g_uiAtomicAPIInitializationCount; + + bResult = true; + } + while (false); + + return bResult; +} + +/*extern*/ void FinalizeAtomicAPI() +{ + OU_ASSERT(g_uiAtomicAPIInitializationCount != 0U); + + if (--g_uiAtomicAPIInitializationCount == 0) // Initialization/finalization must be called from main thread + { + FinalizeAtomicAPIValidated(); + } +} + + +#else // #if defined(__OU_ATOMIC_PTR_FUNCTIONS_DEFINED) + +#if !defined(__OU_ATOMIC_ORD32_FUNCTIONS_DEFINED) + +#error Internal error (Atomic ord32 functions can not be undefined while pointer functions are defined) + + +#endif // #if !defined(__OU_ATOMIC_ORD32_FUNCTIONS_DEFINED) + + +#if defined(__OU_ATOMIC_INITIALIZATION_FUNCTIONS_REQUIRED) + +#error Internal error (Atomic initialization can not be required while atomic functions are defined) + + +#endif // #if defined(__OU_ATOMIC_INITIALIZATION_FUNCTIONS_REQUIRED) + + +#endif // #if !defined(__OU_ATOMIC_PTR_FUNCTIONS_DEFINED) + + +END_NAMESPACE_OU(); + + +#endif // #if _OU_FEATURE_SET >= _OU_FEATURE_SET_ATOMICS + diff --git a/libs/ode-0.16.1/ou/src/ou/customization.cpp b/libs/ode-0.16.1/ou/src/ou/customization.cpp new file mode 100644 index 0000000..31f1342 --- /dev/null +++ b/libs/ode-0.16.1/ou/src/ou/customization.cpp @@ -0,0 +1,64 @@ +/************************************************************************* + * * + * ODER's Utilities Library. Copyright (C) 2008-2019 Oleh Derevenko. * + * All rights reserved. e-mail: odar@eleks.com (change all "a" to "e") * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 3 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE-LESSER.TXT. Since LGPL is the extension of GPL * + * the text of GNU General Public License is also provided for * + * your information in file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * (3) The zlib/libpng license that is included with this library in * + * the file LICENSE-ZLIB.TXT * + * * + * This library is distributed WITHOUT ANY WARRANTY, including implied * + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + * See the files LICENSE.TXT and LICENSE-LESSER.TXT or LICENSE-BSD.TXT * + * or LICENSE-ZLIB.TXT for more details. * + * * + *************************************************************************/ + +#include <ou/customization.h> + + +BEGIN_NAMESPACE_OU(); + + +#if !defined(__FILE__) + +// Definition of __FILE__ constant for the case if compiler does not support the macro +/*extern*/ const char *const __FILE__ = "<filename unavailable>"; + + +#endif // #if !defined(__FILE__) + + +#if !defined(__LINE__) + +// Definition of __LINE__ constant for the case if compiler does not support the macro +extern const unsigned int __LINE__ = 0; + + +#endif // #if !defined(__LINE__) + + +////////////////////////////////////////////////////////////////////////// + +/*extern*/ CAssertionFailedProcedure CAssertionCheckCustomization::g_fnAssertFailureHandler = NULL; + + +////////////////////////////////////////////////////////////////////////// + +/*extern*/ CMemoryAllocationProcedure CMemoryManagerCustomization::g_fnMemoryAllocationProcedure = NULL; +/*extern*/ CMemoryReallocationProcedure CMemoryManagerCustomization::g_fnMemoryReallocationProcedure = NULL; +/*extern*/ CMemoryDeallocationProcedure CMemoryManagerCustomization::g_fnMemoryDeallocationProcedure = NULL; + + +END_NAMESPACE_OU(); + diff --git a/libs/ode-0.16.1/ou/src/ou/malloc.cpp b/libs/ode-0.16.1/ou/src/ou/malloc.cpp new file mode 100644 index 0000000..de6d8f5 --- /dev/null +++ b/libs/ode-0.16.1/ou/src/ou/malloc.cpp @@ -0,0 +1,106 @@ +/************************************************************************* + * * + * ODER's Utilities Library. Copyright (C) 2008-2019 Oleh Derevenko. * + * All rights reserved. e-mail: odar@eleks.com (change all "a" to "e") * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 3 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE-LESSER.TXT. Since LGPL is the extension of GPL * + * the text of GNU General Public License is also provided for * + * your information in file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * (3) The zlib/libpng license that is included with this library in * + * the file LICENSE-ZLIB.TXT * + * * + * This library is distributed WITHOUT ANY WARRANTY, including implied * + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + * See the files LICENSE.TXT and LICENSE-LESSER.TXT or LICENSE-BSD.TXT * + * or LICENSE-ZLIB.TXT for more details. * + * * + *************************************************************************/ + +#include <ou/malloc.h> +#include <ou/assert.h> +#include <ou/customization.h> +#include <ou/macros.h> + +#if _OU_TARGET_OS == _OU_TARGET_OS_MAC || _OU_TARGET_OS == _OU_TARGET_OS_IOS + +#include <stdlib.h> + + +#else // #if _OU_TARGET_OS != _OU_TARGET_OS_MAC && _OU_TARGET_OS != _OU_TARGET_OS_IOS + +#include <malloc.h> + + +#endif // #if _OU_TARGET_OS != _OU_TARGET_OS_MAC && _OU_TARGET_OS != _OU_TARGET_OS_IOS + + +BEGIN_NAMESPACE_OU(); + + +/*extern*/ void *_OU_CONVENTION_API AllocateMemoryBlock(size_t nBlockSize) +{ + void *pv_NewBlock; + + CMemoryAllocationProcedure fnMemoryAllocationProcedure = CMemoryManagerCustomization::GetMemoryAllocationCustomProcedure(); + + if (fnMemoryAllocationProcedure) + { + pv_NewBlock = fnMemoryAllocationProcedure(nBlockSize); + OU_ASSERT(OU_ALIGNED_SIZE((size_t)pv_NewBlock, _OU_MEMORY_REQUIRED_ALIGNMENT) == (size_t)pv_NewBlock); // Memory must be aligned + } + else + { + pv_NewBlock = malloc(nBlockSize); + } + + return pv_NewBlock; +} + +/*extern*/ void *_OU_CONVENTION_API ReallocateMemoryBlock(void *pv_ExistingBlock, size_t nNewBlockSize) +{ + OU_ASSERT(OU_ALIGNED_SIZE((size_t)pv_ExistingBlock, _OU_MEMORY_REQUIRED_ALIGNMENT) == (size_t)pv_ExistingBlock); // Memory must be aligned + + void *pv_NewBlock; + + CMemoryReallocationProcedure fnMemoryReallocationProcedure = CMemoryManagerCustomization::GetMemoryReallocationCustomProcedure(); + + if (fnMemoryReallocationProcedure) + { + pv_NewBlock = fnMemoryReallocationProcedure(pv_ExistingBlock, nNewBlockSize); + OU_ASSERT(OU_ALIGNED_SIZE((size_t)pv_NewBlock, _OU_MEMORY_REQUIRED_ALIGNMENT) == (size_t)pv_NewBlock); // Memory must be aligned + } + else + { + pv_NewBlock = realloc(pv_ExistingBlock, nNewBlockSize); + } + + return pv_NewBlock; +} + +/*extern*/ void _OU_CONVENTION_API FreeMemoryBlock(void *pv_ExistingBlock) +{ + OU_ASSERT(OU_ALIGNED_SIZE((size_t)pv_ExistingBlock, _OU_MEMORY_REQUIRED_ALIGNMENT) == (size_t)pv_ExistingBlock); // Memory must be aligned + + CMemoryDeallocationProcedure fnMemoryDeallocationProcedure = CMemoryManagerCustomization::GetMemoryDeallocationCustomProcedure(); + + if (fnMemoryDeallocationProcedure) + { + fnMemoryDeallocationProcedure(pv_ExistingBlock); + } + else + { + free(pv_ExistingBlock); + } +} + + +END_NAMESPACE_OU(); + diff --git a/libs/ode-0.16.1/ou/src/ou/threadlocalstorage.cpp b/libs/ode-0.16.1/ou/src/ou/threadlocalstorage.cpp new file mode 100644 index 0000000..49d033a --- /dev/null +++ b/libs/ode-0.16.1/ou/src/ou/threadlocalstorage.cpp @@ -0,0 +1,1336 @@ +/************************************************************************* + * * + * ODER's Utilities Library. Copyright (C) 2008-2019 Oleh Derevenko. * + * All rights reserved. e-mail: odar@eleks.com (change all "a" to "e") * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 3 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE-LESSER.TXT. Since LGPL is the extension of GPL * + * the text of GNU General Public License is also provided for * + * your information in file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * (3) The zlib/libpng license that is included with this library in * + * the file LICENSE-ZLIB.TXT * + * * + * This library is distributed WITHOUT ANY WARRANTY, including implied * + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + * See the files LICENSE.TXT and LICENSE-LESSER.TXT or LICENSE-BSD.TXT * + * or LICENSE-ZLIB.TXT for more details. * + * * + *************************************************************************/ + +#include <ou/features.h> + + +#if _OU_FEATURE_SET >= _OU_FEATURE_SET_TLS + +#include <ou/threadlocalstorage.h> +#include <ou/atomicflags.h> +#include <ou/atomic.h> +#include <ou/simpleflags.h> +#include <ou/malloc.h> +#include <ou/templates.h> +#include <ou/inttypes.h> + +#include <string.h> +#include <errno.h> +#include <new> + +#if !defined(EOK) + +#define EOK 0 + + +#endif + + +#if _OU_TARGET_OS == _OU_TARGET_OS_WINDOWS + +#include <windows.h> + + +#endif // #if _OU_TARGET_OS == _OU_TARGET_OS_WINDOWS + + +BEGIN_NAMESPACE_OU(); + + +class CTLSStorageInstance; + +enum ESTORAGEINSTANCEKIND +{ + SIK__MIN, + + SIK_AUTOCLEANUP = SIK__MIN, + SIK_MANUALCLEANUP, + + SIK__MAX, +}; + + +static unsigned int g_uiThreadLocalStorageInitializationCount = 0; +static CTLSStorageInstance *g_apsiStorageGlobalInstances[SIK__MAX] = { NULL }; +static HTLSKEYVALUE g_ahkvStorageGlobalKeyValues[SIK__MAX] = { NULL }; + + +static inline size_t DecodeInstanceKindFromKeySelector(const HTLSKEYSELECTOR &hksKeySelector) +{ + return (HTLSKEYSELECTOR::value_type)hksKeySelector - g_ahkvStorageGlobalKeyValues; +} + +static inline HTLSKEYSELECTOR EncodeKeySelectorFromStorageKind(ESTORAGEINSTANCEKIND ikInstanceKind) +{ + return g_ahkvStorageGlobalKeyValues + ikInstanceKind; +} + + +#if !defined(_OU_TLS_ARRAY_ELEMENT_COUNT) + +// Default TLS array element count +#define _OU_TLS_ARRAY_ELEMENT_COUNT 8 + + +#endif // #if !defined(_OU_TLS_ARRAY_ELEMENT_COUNT) + + +// Few bits must be reserved for additional purposes (currently 1) +#if (_OU_TLS_ARRAY_ELEMENT_COUNT < 1) || (_OU_TLS_ARRAY_ELEMENT_COUNT > 30) + +#error Please specify TLS array element count in range from 1 to 30 + + +#endif // #if (_OU_TLS_ARRAY_ELEMENT_COUNT < 1) || (_OU_TLS_ARRAY_ELEMENT_COUNT > 30) + + +enum +{ + TLS_ARRAY_ELEMENT__MAX = _OU_TLS_ARRAY_ELEMENT_COUNT, // 16 threads with 8 values each using 4 + 4 bytes is ~1 kb of memory +}; + + +struct CTLSStorageArray +{ +private: +#if _OU_TARGET_OS == _OU_TARGET_OS_WINDOWS + + typedef HANDLE CClientHandleArray[TLS_ARRAY_ELEMENT__MAX]; + typedef unsigned int CHandleTranslationMap[TLS_ARRAY_ELEMENT__MAX]; + + +#endif // #if _OU_TARGET_OS == _OU_TARGET_OS_WINDOWS + +public: + static inline size_t GetHeaderSize() { return OU_ALIGNED_SIZE(sizeof(CTLSStorageArray), CTLSStorageBlock::TSB_LARGEST_ALIGNMENT); } + +public: + static CTLSStorageArray *AllocateInstance(tlsindextype iValueCount); + void FreeInstance(tlsindextype iValueCount); + +protected: + inline CTLSStorageArray(); // Use AllocateInstance() + inline ~CTLSStorageArray(); // Use FreeInstance() + +public: + void FreeStorageBlockOnThreadExit(CTLSStorageBlock *psbStorageBlock, tlsindextype iValueCount); + +public: + bool FindFreeStorageBlock(CTLSStorageBlock *&psbOutFreeStorageBlock, + tlsindextype iValueCount, bool bIsManualCleanup); + +private: + bool FindFreeStorageBlockIndex(unsigned int &nOutFreeBlockIndex, tlsindextype iValueCount, bool bIsManualCleanup); + bool FindFreeStorageBlockIndexWithPossibilityVerified(unsigned int &nOutFreeBlockIndex, bool bIsManualCleanup); +#if _OU_TARGET_OS == _OU_TARGET_OS_WINDOWS + + bool FindAbandonedStorageBlockIndex(unsigned int &nOutFreeBlockIndex, tlsindextype iValueCount); + unsigned int TranslateClientHandles(CClientHandleArray haTranslatedHandlesStorage, CHandleTranslationMap tmTranslationMapStorage, + const HANDLE *&ph_OutTranslatedHandles, const unsigned int *&puiOutTranslationMap) const; + +#endif // #if _OU_TARGET_OS == _OU_TARGET_OS_WINDOWS + +private: + void FreeStorageAllBlocks(tlsindextype iValueCount); + void ReinitializeStorageSingleBlock(CTLSStorageBlock *psbStorageBlock, tlsindextype iValueCount); + static void FinalizeStorageSingleBlock(CTLSStorageBlock *psbStorageBlock, tlsindextype iValueCount); + + void AssignAllBlocksHostArray(tlsindextype iValueCount); + inline void AssignSingleBlockHostArray(CTLSStorageBlock *psbStorageBlock); + +private: + inline CTLSStorageBlock *GetStorageBlockPointer(unsigned int nBlockIndex, tlsindextype iValueCount) const; + inline unsigned int GetStorageBlockIndex(CTLSStorageBlock *psbStorageBlock, tlsindextype iValueCount) const; + inline static void ZeroStorageBlockMemory(CTLSStorageBlock *psbStorageBlock, tlsindextype iValueCount); + +private: +#if _OU_TARGET_OS == _OU_TARGET_OS_WINDOWS + + void AllocateBlockThreadHandle(unsigned int nBlockIndex); + void FreeStorageThreadHandle(unsigned int nBlockIndex); + + void AssignAllBlocksInvalidThreads(); + bool CheckIfAllBlocksHaveInvalidThreads(); + +#endif // #if _OU_TARGET_OS == _OU_TARGET_OS_WINDOWS + +private: +#if _OU_TARGET_OS == _OU_TARGET_OS_WINDOWS + + inline void SetBlockThreadHandle(unsigned int nBlockIndex, HANDLE hValue) + { + m_haBlockThreads[nBlockIndex] = hValue; + } + + inline HANDLE GetBlockThreadHandle(unsigned int nBlockIndex) const + { + return m_haBlockThreads[nBlockIndex]; + } + + inline const HANDLE *GetBlockThreadHandlesStorage() const + { + return m_haBlockThreads; + } + +#endif // #if _OU_TARGET_OS == _OU_TARGET_OS_WINDOWS + +public: + inline void SetNextArray(CTLSStorageArray *psaInstance) + { + m_psaNextArray = (atomicptr)psaInstance; + } + + inline CTLSStorageArray *GetNextArray() const + { + return (CTLSStorageArray *)m_psaNextArray; + } + +private: + enum + { + FL_OCCUPANCY_FLAGS__START = 0x00000001, + FL_OCCUPANCY_FLAGS__END = FL_OCCUPANCY_FLAGS__START << TLS_ARRAY_ELEMENT__MAX, + + FL_ARRAY_LOCKED = FL_OCCUPANCY_FLAGS__END, + }; + + inline bool GetAreAllBlocksOccupied() const + { + return m_afOccupancyFlags.EnumAllQueryEnumeratedFlags(FL_OCCUPANCY_FLAGS__START, TLS_ARRAY_ELEMENT__MAX) == OU_FLAGS_ENUMFLAGS_MASK(COccupancyFlagsType::value_type, FL_OCCUPANCY_FLAGS__START, TLS_ARRAY_ELEMENT__MAX); + } + + inline bool GetIsAnyBlockOccupied() const + { + return m_afOccupancyFlags.EnumAnyGetEnumeratedFlagValue(FL_OCCUPANCY_FLAGS__START, TLS_ARRAY_ELEMENT__MAX); + } + + inline bool SetBlockOccupiedFlag(unsigned int nBlockIndex) + { + return m_afOccupancyFlags.EnumModifyEnumeratedFlagValue(FL_OCCUPANCY_FLAGS__START, nBlockIndex, TLS_ARRAY_ELEMENT__MAX, true); + } + + inline void ResetBlockOccupiedFlag(unsigned int nBlockIndex) + { + m_afOccupancyFlags.EnumDropEnumeratedFlagValue(FL_OCCUPANCY_FLAGS__START, nBlockIndex, TLS_ARRAY_ELEMENT__MAX); + } + + inline bool GetBlockOccupiedFlag(unsigned int nBlockIndex) const + { + return m_afOccupancyFlags.EnumGetEnumeratedFlagValue(FL_OCCUPANCY_FLAGS__START, nBlockIndex, TLS_ARRAY_ELEMENT__MAX); + } + + inline bool SetArrayLockedFlag() + { + return m_afOccupancyFlags.ModifySingleFlagValue(FL_ARRAY_LOCKED, true); + } + + inline void ResetArrayLockedFlag() + { + m_afOccupancyFlags.DropFlagsMaskValue(FL_ARRAY_LOCKED); + } + +private: + typedef CAtomicFlags COccupancyFlagsType; + + volatile atomicptr m_psaNextArray; // CTLSStorageArray * + COccupancyFlagsType m_afOccupancyFlags; + +#if _OU_TARGET_OS == _OU_TARGET_OS_WINDOWS + + CClientHandleArray m_haBlockThreads; + + +#endif // #if _OU_TARGET_OS == _OU_TARGET_OS_WINDOWS + + // CTLSStorageBlock m_asbStorageBlocks[]; +}; + +class CTLSStorageInstance +{ +public: + static CTLSStorageInstance *AllocateInstance(tlsindextype iValueCount, unsigned int uiInitializationFlags); + void FreeInstance(); + +protected: + CTLSStorageInstance(tlsindextype iValueCount, unsigned int uiInitializationFlags); + ~CTLSStorageInstance(); + +public: + bool Init(ESTORAGEINSTANCEKIND ikInstanceKind); + +private: + void Finit(); + +public: + inline const HTLSKEYVALUE &RetrieveStorageKey() const { return GetStorageKey(); } + inline tlsindextype RetrieveValueCount() const { return GetValueCount(); } + inline unsigned int RetrieveInitializationFlags() const { return GetInitializationFlags(); } + + inline bool GetIsThreadManualCleanup() const { return GetThreadManualCleanupFlag(); } + +public: + void FreeStorageBlockOnThreadExit(CTLSStorageBlock *psbStorageBlock); + +public: + bool FindFreeStorageBlock(CTLSStorageBlock *&psbOutStorageBlock); + +private: + bool FindFreeStorageBlockInArrayList(CTLSStorageBlock *&psbOutStorageBlock); + bool FindFreeStorageBlockInArrayListSegment(CTLSStorageBlock *&psbOutStorageBlock, + CTLSStorageArray *psaListSegmentBegin, CTLSStorageArray *psaListSegmentEnd); + bool FindFreeStorageBlockFromArray(CTLSStorageBlock *&psbOutStorageBlock, + CTLSStorageArray *psaArrayInstance); + + void AddStorageArrayToArrayList(CTLSStorageArray *psaStorageArray); + +private: + static bool AllocateStorageKey(HTLSKEYVALUE &hkvOutStorageKey, ESTORAGEINSTANCEKIND ikInstanceKind); + static void FreeStorageKey(const HTLSKEYVALUE &hkvStorageKey); + +#if _OU_TARGET_OS != _OU_TARGET_OS_WINDOWS + + static void FreeStorageBlock_Callback_Automatic(void *pv_DataValue); + static void FreeStorageBlock_Callback_Manual(void *pv_DataValue); + + +#endif // #if _OU_TARGET_OS != _OU_TARGET_OS_WINDOWS + + void FreeStorageBlock(CTLSStorageBlock *psbStorageBlock); + + CTLSStorageArray *AllocateStorageArray(); + void FreeStorageArrayList(CTLSStorageArray *psaStorageArrayList); + +private: + inline bool TrySettingStorageArrayList(CTLSStorageArray *psaInstance, CTLSStorageArray *psaCurrentList) + { + return AtomicCompareExchangePointer(&m_psaStorageList, (atomicptr)psaCurrentList, (atomicptr)psaInstance); + } + + inline CTLSStorageArray *GetStorageArrayList() const + { + return (CTLSStorageArray *)m_psaStorageList; + } + + inline void SetStorageKey(const HTLSKEYVALUE &hskValue) { m_hskStorageKey = hskValue; } + inline const HTLSKEYVALUE &GetStorageKey() const { return m_hskStorageKey; } + + inline tlsindextype GetValueCount() const { return m_iValueCount; } + +private: + enum + { + FL_STORAGE_KEY_VALID = 0x00000001, + + FLM_INITIALIZATION_FLAGS_MASK = 0x0000FFFF, + FLS_INITIALIZATION_FLAGS_SHIFT = 16, + + FL_INITIALIZATION_THREAD_MANUAL_CLEANUP = CTLSInitialization::SIF_MANUAL_CLEANUP_ON_THREAD_EXIT << FLS_INITIALIZATION_FLAGS_SHIFT, + }; + + inline void SetStorageKeyValidFlag() { m_sfInstanceFlags.SignalFlagsMaskValue(FL_STORAGE_KEY_VALID); } + inline void ResetStorageKeyValidFlag() { m_sfInstanceFlags.DropFlagsMaskValue(FL_STORAGE_KEY_VALID); } + inline bool GetStorageKeyValidFlag() const { return m_sfInstanceFlags.GetFlagsMaskValue(FL_STORAGE_KEY_VALID); } + + inline void SetInitializationFlags(unsigned int uiValue) { m_sfInstanceFlags.StoreFlagsEnumeratedValue(FLM_INITIALIZATION_FLAGS_MASK, FLS_INITIALIZATION_FLAGS_SHIFT, uiValue); } + inline unsigned int GetInitializationFlags() const { return m_sfInstanceFlags.RetrieveFlagsEnumeratedValue(FLM_INITIALIZATION_FLAGS_MASK, FLS_INITIALIZATION_FLAGS_SHIFT); } + + inline bool GetThreadManualCleanupFlag() const { return m_sfInstanceFlags.GetFlagsMaskValue(FL_INITIALIZATION_THREAD_MANUAL_CLEANUP); } + +private: + volatile atomicptr m_psaStorageList; // CTLSStorageArray * + HTLSKEYVALUE m_hskStorageKey; + CSimpleFlags m_sfInstanceFlags; + tlsindextype m_iValueCount; +}; + + +////////////////////////////////////////////////////////////////////////// +// CTLSStorageArray methods + +CTLSStorageArray *CTLSStorageArray::AllocateInstance(tlsindextype iValueCount) +{ + const size_t nHeaderSize = CTLSStorageArray::GetHeaderSize(); + const size_t nBlockSize = CTLSStorageBlock::GetRequiredSize(iValueCount); + size_t nRequiredSize = nHeaderSize + nBlockSize * TLS_ARRAY_ELEMENT__MAX; + + CTLSStorageArray *psaNewInstance = (CTLSStorageArray *)AllocateMemoryBlock(nRequiredSize); + + if (psaNewInstance) + { + memset(psaNewInstance, 0, nRequiredSize); + new((CTLSStorageArray *)psaNewInstance) CTLSStorageArray(); + + psaNewInstance->AssignAllBlocksHostArray(iValueCount); + } + + return psaNewInstance; +} + +void CTLSStorageArray::FreeInstance(tlsindextype iValueCount) +{ + if (GetIsAnyBlockOccupied()) + { + FreeStorageAllBlocks(iValueCount); + } + + this->CTLSStorageArray::~CTLSStorageArray(); + FreeMemoryBlock((void *)this); +} + +CTLSStorageArray::CTLSStorageArray() +{ +#if _OU_TARGET_OS == _OU_TARGET_OS_WINDOWS + + AssignAllBlocksInvalidThreads(); + + +#endif // #if _OU_TARGET_OS == _OU_TARGET_OS_WINDOWS +} + +CTLSStorageArray::~CTLSStorageArray() +{ +#if _OU_TARGET_OS == _OU_TARGET_OS_WINDOWS + + OU_ASSERT(CheckIfAllBlocksHaveInvalidThreads()); + + +#endif // #if _OU_TARGET_OS == _OU_TARGET_OS_WINDOWS +} + + +void CTLSStorageArray::FreeStorageBlockOnThreadExit(CTLSStorageBlock *psbStorageBlock, tlsindextype iValueCount) +{ + ReinitializeStorageSingleBlock(psbStorageBlock, iValueCount); + // OU_ASSERT(GetBlockThreadHandle(nBlockIndex) == INVALID_HANDLE_VALUE) -- assertion further in the code + + unsigned int nBlockIndex = GetStorageBlockIndex(psbStorageBlock, iValueCount); + OU_ASSERT(GetBlockOccupiedFlag(nBlockIndex)); +#if _OU_TARGET_OS == _OU_TARGET_OS_WINDOWS + + OU_ASSERT(GetBlockThreadHandle(nBlockIndex) == INVALID_HANDLE_VALUE); // The method is not to be called if automatic cleanup is enabled + + +#endif // #if _OU_TARGET_OS == _OU_TARGET_OS_WINDOWS + + ResetBlockOccupiedFlag(nBlockIndex); +} + + +bool CTLSStorageArray::FindFreeStorageBlock(CTLSStorageBlock *&psbOutFreeStorageBlock, + tlsindextype iValueCount, bool bIsManualCleanup) +{ + bool bResult = false; + + unsigned int nFreeBlockIndex; + + if (FindFreeStorageBlockIndex(nFreeBlockIndex, iValueCount, bIsManualCleanup)) + { + CTLSStorageBlock *psbFreeStorageBlock = GetStorageBlockPointer(nFreeBlockIndex, iValueCount); + + psbOutFreeStorageBlock = psbFreeStorageBlock; + bResult = true; + } + + return bResult; +} + + +bool CTLSStorageArray::FindFreeStorageBlockIndex(unsigned int &nOutFreeBlockIndex, + tlsindextype iValueCount, bool bIsManualCleanup) +{ + bool bResult = false; + + if (!GetAreAllBlocksOccupied() && FindFreeStorageBlockIndexWithPossibilityVerified(nOutFreeBlockIndex, bIsManualCleanup)) + { + bResult = true; + } +#if _OU_TARGET_OS == _OU_TARGET_OS_WINDOWS + + else if (!bIsManualCleanup) + { + // Execution gets here is all slots were already occupied or + // they become occupied during search (otherwise why + // FindFreeStorageBlockIndexWithPossibilityVerified call failed???). + // In Automatic cleanup mode a block can't become free by itself - + // it is just re-allocated for new thread and remains busy. + OU_ASSERT(GetAreAllBlocksOccupied()); + + // The locking is performed to avoid more than one threads checking + // for abandoned handles simultaneously. + // If locking fails, execution just proceeds to next array in the chain + if (SetArrayLockedFlag()) + { + bResult = FindAbandonedStorageBlockIndex(nOutFreeBlockIndex, iValueCount); + + ResetArrayLockedFlag(); + } + } + + +#endif // #if _OU_TARGET_OS == _OU_TARGET_OS_WINDOWS + + return bResult; +} + +bool CTLSStorageArray::FindFreeStorageBlockIndexWithPossibilityVerified(unsigned int &nOutFreeBlockIndex, + bool bIsManualCleanup) +{ + unsigned int nBlockIndex = 0; + + for (; nBlockIndex != TLS_ARRAY_ELEMENT__MAX; ++nBlockIndex) + { + if (SetBlockOccupiedFlag(nBlockIndex)) + { +#if _OU_TARGET_OS == _OU_TARGET_OS_WINDOWS + + if (!bIsManualCleanup) + { + AllocateBlockThreadHandle(nBlockIndex); + } + + +#endif // #if _OU_TARGET_OS == _OU_TARGET_OS_WINDOWS + + nOutFreeBlockIndex = nBlockIndex; + break; + } + } + + bool bResult = nBlockIndex != TLS_ARRAY_ELEMENT__MAX; + return bResult; +} + + +#if _OU_TARGET_OS == _OU_TARGET_OS_WINDOWS + +bool CTLSStorageArray::FindAbandonedStorageBlockIndex(unsigned int &nOutFreeBlockIndex, + tlsindextype iValueCount) +{ + bool bResult = false; + + do + { + CClientHandleArray haTranslatedHandlesStorage; + CHandleTranslationMap tmTranslationMapStorage; + + const HANDLE *ph_TranslatedHandles; + const unsigned int *puiTranslationMap; + + // Translate handles into array for the case if there are invalids + unsigned int nHandleCount = TranslateClientHandles(haTranslatedHandlesStorage, tmTranslationMapStorage, + ph_TranslatedHandles, puiTranslationMap); + OU_ASSERT(OU_IN_INT_RANGE(nHandleCount, 0, MAXIMUM_WAIT_OBJECTS + 1)); + + if (nHandleCount == 0) + { + break; + } + + // Since allocating a new storage block is a relatively slow operation + // it is acceptable to enter kernel for checking for exited threads. + DWORD dwWaitResult = ::WaitForMultipleObjects(nHandleCount, ph_TranslatedHandles, FALSE, 0); + + if (!OU_IN_INT_RANGE(dwWaitResult - WAIT_OBJECT_0, 0, nHandleCount)) + { + // Wait should not normally fail. If it does it's in most cases an indication + // of invalid handle passed as parameter. However it may fail because of other + // reasons as well. If this assertion fails too often and you are sure all the + // handles are valid, it is safe to comment it. + OU_ASSERT(dwWaitResult != WAIT_FAILED); + + break; + } + + unsigned int nTranslatedBlockIndex = (unsigned int)(dwWaitResult - WAIT_OBJECT_0); + unsigned int nBlockIndex = !puiTranslationMap ? nTranslatedBlockIndex : puiTranslationMap[nTranslatedBlockIndex]; + + CTLSStorageBlock *psbStorageBlock = GetStorageBlockPointer(nBlockIndex, iValueCount); + ReinitializeStorageSingleBlock(psbStorageBlock, iValueCount); + + // Close old handle and make a duplicate of current thread handle + FreeStorageThreadHandle(nBlockIndex); + AllocateBlockThreadHandle(nBlockIndex); + + nOutFreeBlockIndex = nBlockIndex; + bResult = true; + } + while (false); + + return bResult; +} + +unsigned int CTLSStorageArray::TranslateClientHandles(CClientHandleArray haTranslatedHandlesStorage, CHandleTranslationMap tmTranslationMapStorage, + const HANDLE *&ph_OutTranslatedHandles, const unsigned int *&puiOutTranslationMap) const +{ + ph_OutTranslatedHandles = haTranslatedHandlesStorage; + puiOutTranslationMap = tmTranslationMapStorage; + + unsigned int nTargetStartIndex = 0; + unsigned int nSourceStartIndex = 0, nSourceCurrentIndex = 0; + + while (true) + { + if (GetBlockThreadHandle(nSourceCurrentIndex) == INVALID_HANDLE_VALUE) + { + const HANDLE *ph_BlockThreadHandles = GetBlockThreadHandlesStorage(); + + unsigned int nTargetIncrement = nSourceCurrentIndex - nSourceStartIndex; + + memcpy(&haTranslatedHandlesStorage[nTargetStartIndex], &ph_BlockThreadHandles[nSourceStartIndex], nTargetIncrement * sizeof(HANDLE)); + for (; nTargetIncrement != 0; ++nTargetStartIndex, ++nSourceStartIndex, --nTargetIncrement) { tmTranslationMapStorage[nTargetStartIndex] = nSourceStartIndex; } + + // Skip invalid handle (at this point nSourceStartIndex is equal to nSourceCurrentIndex) + ++nSourceStartIndex; + } + + ++nSourceCurrentIndex; + + if (nSourceCurrentIndex == TLS_ARRAY_ELEMENT__MAX) + { + // Start indice can be equal if and only if no invalid handles have been found + if (nSourceStartIndex != nTargetStartIndex) + { + const HANDLE *ph_BlockThreadHandles = GetBlockThreadHandlesStorage(); + + unsigned int nTargetIncrement = nSourceCurrentIndex - nSourceStartIndex; + + memcpy(&haTranslatedHandlesStorage[nTargetStartIndex], &ph_BlockThreadHandles[nSourceStartIndex], nTargetIncrement * sizeof(HANDLE)); + for (; nTargetIncrement != 0; ++nTargetStartIndex, ++nSourceStartIndex, --nTargetIncrement) { tmTranslationMapStorage[nTargetStartIndex] = nSourceStartIndex; } + } + + break; + } + } + + // If all the handles are valid... + if (nTargetStartIndex == 0) + { + // ...just return original handle array as no copying was performed + ph_OutTranslatedHandles = GetBlockThreadHandlesStorage(); + puiOutTranslationMap = NULL; + } + + return nTargetStartIndex; +} + + +#endif // #if _OU_TARGET_OS == _OU_TARGET_OS_WINDOWS + + +void CTLSStorageArray::FreeStorageAllBlocks(tlsindextype iValueCount) +{ + for (unsigned int nBlockIndex = 0; nBlockIndex != TLS_ARRAY_ELEMENT__MAX; ++nBlockIndex) + { + if (GetBlockOccupiedFlag(nBlockIndex)) + { + CTLSStorageBlock *psbStorageBlock = GetStorageBlockPointer(nBlockIndex, iValueCount); + + FinalizeStorageSingleBlock(psbStorageBlock, iValueCount); +#if _OU_TARGET_OS == _OU_TARGET_OS_WINDOWS + + FreeStorageThreadHandle(nBlockIndex); + + +#endif // #if _OU_TARGET_OS == _OU_TARGET_OS_WINDOWS + } + else + { +#if _OU_TARGET_OS == _OU_TARGET_OS_WINDOWS + + OU_ASSERT(GetBlockThreadHandle(nBlockIndex) == INVALID_HANDLE_VALUE); // Where did the handle come from if block is not occupied? + + +#endif // #if _OU_TARGET_OS == _OU_TARGET_OS_WINDOWS + } + } +} + +void CTLSStorageArray::ReinitializeStorageSingleBlock(CTLSStorageBlock *psbStorageBlock, tlsindextype iValueCount) +{ + FinalizeStorageSingleBlock(psbStorageBlock, iValueCount); + + ZeroStorageBlockMemory(psbStorageBlock, iValueCount); + AssignSingleBlockHostArray(psbStorageBlock); +} + +void CTLSStorageArray::FinalizeStorageSingleBlock(CTLSStorageBlock *psbStorageBlock, tlsindextype iValueCount) +{ + for (tlsindextype iValueIndex = 0; iValueIndex != iValueCount; ++iValueIndex) + { + tlsvaluetype vValueData = psbStorageBlock->GetValueData(iValueIndex); + + if (vValueData) + { + CTLSValueDestructor fnValueDestructor = psbStorageBlock->GetValueDestructor(iValueIndex); + + if (fnValueDestructor) + { + fnValueDestructor(vValueData); + } + } + } +} + + +void CTLSStorageArray::AssignAllBlocksHostArray(tlsindextype iValueCount) +{ + for (unsigned int nBlockIndex = 0; nBlockIndex != TLS_ARRAY_ELEMENT__MAX; ++nBlockIndex) + { + CTLSStorageBlock *psbStorageBlock = GetStorageBlockPointer(nBlockIndex, iValueCount); + + AssignSingleBlockHostArray(psbStorageBlock); + } +} + +void CTLSStorageArray::AssignSingleBlockHostArray(CTLSStorageBlock *psbStorageBlock) +{ + psbStorageBlock->SetHostArray(this); +} + + +CTLSStorageBlock *CTLSStorageArray::GetStorageBlockPointer(unsigned int nBlockIndex, tlsindextype iValueCount) const +{ + OU_ASSERT(OU_IN_INT_RANGE(nBlockIndex, 0, TLS_ARRAY_ELEMENT__MAX)); + + const size_t nHeaderSize = CTLSStorageArray::GetHeaderSize(); + const size_t nBlockSize = CTLSStorageBlock::GetRequiredSize(iValueCount); + const size_t nBlockZeroOffset = CTLSStorageBlock::GetZeroOffset(iValueCount); + + CTLSStorageBlock *psbStorageBlock = (CTLSStorageBlock *)(((int8ou *)this) + nHeaderSize + nBlockIndex * nBlockSize + nBlockZeroOffset); + return psbStorageBlock; +} + +unsigned int CTLSStorageArray::GetStorageBlockIndex(CTLSStorageBlock *psbStorageBlock, tlsindextype iValueCount) const +{ + const size_t nHeaderSize = CTLSStorageArray::GetHeaderSize(); + const size_t nBlockSize = CTLSStorageBlock::GetRequiredSize(iValueCount); + const size_t nBlockZeroOffset = CTLSStorageBlock::GetZeroOffset(iValueCount); + + unsigned int uiBlockIndex = (unsigned int)((((int8ou *)psbStorageBlock) - nBlockZeroOffset - nHeaderSize - ((int8ou *)this)) / nBlockSize); + OU_ASSERT((((int8ou *)psbStorageBlock) - nBlockZeroOffset - nHeaderSize - ((int8ou *)this)) % nBlockSize == 0); + OU_ASSERT(OU_IN_INT_RANGE(uiBlockIndex, 0, TLS_ARRAY_ELEMENT__MAX)); + + return uiBlockIndex; +} + +void CTLSStorageArray::ZeroStorageBlockMemory(CTLSStorageBlock *psbStorageBlock, tlsindextype iValueCount) +{ + const size_t nBlockSize = CTLSStorageBlock::GetRequiredSize(iValueCount); + const size_t nBlockZeroOffset = CTLSStorageBlock::GetZeroOffset(iValueCount); + + memset(((int8ou *)psbStorageBlock) - nBlockZeroOffset, 0, nBlockSize); +} + + +#if _OU_TARGET_OS == _OU_TARGET_OS_WINDOWS + +void CTLSStorageArray::AllocateBlockThreadHandle(unsigned int nBlockIndex) +{ + OU_ASSERT(GetBlockThreadHandle(nBlockIndex) == INVALID_HANDLE_VALUE); + + HANDLE hCurrentThreadDuplicate; + + HANDLE hCurrentProcess = ::GetCurrentProcess(); + HANDLE hCurrentThread = ::GetCurrentThread(); + if (!::DuplicateHandle(hCurrentProcess, hCurrentThread, hCurrentProcess, &hCurrentThreadDuplicate, SYNCHRONIZE, FALSE, 0)) + { + // Handle duplication should not normally fail. + // Thread and process pseudo-handles have full access allowed. + // The duplication may only fail in case of kernel internal problems + // (like lack of the resources or resource limit hits). + // Well, in this case thread data will remain in memory until + // CTLSInitialization::FinalizeTLSAPI() is called. + hCurrentThreadDuplicate = INVALID_HANDLE_VALUE; + } + + SetBlockThreadHandle(nBlockIndex, hCurrentThreadDuplicate); +} + +void CTLSStorageArray::FreeStorageThreadHandle(unsigned int nBlockIndex) +{ + HANDLE hExistingThreadHandle = GetBlockThreadHandle(nBlockIndex); + + if (hExistingThreadHandle != INVALID_HANDLE_VALUE) + { + BOOL bHandleCloseResult = ::CloseHandle(hExistingThreadHandle); + OU_VERIFY(bHandleCloseResult); // Closing handle should normally succeed + + SetBlockThreadHandle(nBlockIndex, INVALID_HANDLE_VALUE); + } +} + + +void CTLSStorageArray::AssignAllBlocksInvalidThreads() +{ + for (unsigned int nBlockIndex = 0; nBlockIndex != TLS_ARRAY_ELEMENT__MAX; ++nBlockIndex) + { + SetBlockThreadHandle(nBlockIndex, INVALID_HANDLE_VALUE); + } +} + +bool CTLSStorageArray::CheckIfAllBlocksHaveInvalidThreads() +{ + unsigned nBlockIndex = 0; + + for (; nBlockIndex != TLS_ARRAY_ELEMENT__MAX; ++nBlockIndex) + { + if (GetBlockThreadHandle(nBlockIndex) != INVALID_HANDLE_VALUE) + { + break; + } + } + + bool bResult = nBlockIndex == TLS_ARRAY_ELEMENT__MAX; + return bResult; +} + + +#endif // #if _OU_TARGET_OS == _OU_TARGET_OS_WINDOWS + + +////////////////////////////////////////////////////////////////////////// +// CTLSStorageInstance methods + +CTLSStorageInstance *CTLSStorageInstance::AllocateInstance(tlsindextype iValueCount, unsigned int uiInitializationFlags) +{ + size_t nSizeRequired = sizeof(CTLSStorageInstance); + + CTLSStorageInstance *psiNewInstance = (CTLSStorageInstance *)AllocateMemoryBlock(nSizeRequired); + + if (psiNewInstance) + { + new(psiNewInstance) CTLSStorageInstance(iValueCount, uiInitializationFlags); + } + + return psiNewInstance; +} + +void CTLSStorageInstance::FreeInstance() +{ + this->CTLSStorageInstance::~CTLSStorageInstance(); + FreeMemoryBlock(this); +} + + +CTLSStorageInstance::CTLSStorageInstance(tlsindextype iValueCount, unsigned int uiInitializationFlags): + m_psaStorageList((atomicptr)0), + m_hskStorageKey((HTLSKEYVALUE::value_type)0), + m_iValueCount(iValueCount) +{ + SetInitializationFlags(uiInitializationFlags); +} + +CTLSStorageInstance::~CTLSStorageInstance() +{ + Finit(); +} + + +bool CTLSStorageInstance::Init(ESTORAGEINSTANCEKIND ikInstanceKind) +{ + bool bResult = false; + + bool bKeyAllocationResult = false; + HTLSKEYVALUE hkvStorageKey; + + do + { + if (!AllocateStorageKey(hkvStorageKey, ikInstanceKind)) + { + break; + } + + bKeyAllocationResult = true; + + CTLSStorageArray *psaFirstStorageArray = AllocateStorageArray(); + + if (!psaFirstStorageArray) + { + break; + } + + SetStorageKey(hkvStorageKey); + SetStorageKeyValidFlag(); + AddStorageArrayToArrayList(psaFirstStorageArray); + + bResult = true; + } + while (false); + + if (!bResult) + { + if (bKeyAllocationResult) + { + FreeStorageKey(hkvStorageKey); + } + } + + return bResult; +} + +void CTLSStorageInstance::Finit() +{ + CTLSStorageArray *psaStorageArrayList = GetStorageArrayList(); + + if (psaStorageArrayList) + { + FreeStorageArrayList(psaStorageArrayList); + + bool bListClearingResult = TrySettingStorageArrayList(NULL, psaStorageArrayList); // It could be assigned directly, but I just do not want to add an extra method + OU_VERIFY(bListClearingResult); + } + + if (GetStorageKeyValidFlag()) + { + const HTLSKEYVALUE &hkvStorageKey = GetStorageKey(); + FreeStorageKey(hkvStorageKey); + + ResetStorageKeyValidFlag(); + } +} + + +void CTLSStorageInstance::FreeStorageBlockOnThreadExit(CTLSStorageBlock *psbStorageBlock) +{ + FreeStorageBlock(psbStorageBlock); +} + + +bool CTLSStorageInstance::FindFreeStorageBlock(CTLSStorageBlock *&psbOutStorageBlock) +{ + bool bResult = false; + + do + { + if (!FindFreeStorageBlockInArrayList(psbOutStorageBlock)) + { + CTLSStorageArray *psaStorageArray = AllocateStorageArray(); + + if (!psaStorageArray) + { + break; + } + + FindFreeStorageBlockFromArray(psbOutStorageBlock, psaStorageArray); // Must always succeed as array is not added to list yet + + AddStorageArrayToArrayList(psaStorageArray); + } + + bResult = true; + } + while (false); + + return bResult; +} + +bool CTLSStorageInstance::FindFreeStorageBlockInArrayList(CTLSStorageBlock *&psbOutStorageBlock) +{ + bool bResult; + + CTLSStorageArray *psaListOldHead = NULL; + CTLSStorageArray *psaListCurrentHead = GetStorageArrayList(); + + while (true) + { + if (FindFreeStorageBlockInArrayListSegment(psbOutStorageBlock, psaListCurrentHead, psaListOldHead)) + { + bResult = true; + break; + } + + psaListOldHead = psaListCurrentHead; + psaListCurrentHead = GetStorageArrayList(); + + if (psaListOldHead == psaListCurrentHead) + { + bResult = false; + break; + } + } + + return bResult; +} + +bool CTLSStorageInstance::FindFreeStorageBlockInArrayListSegment(CTLSStorageBlock *&psbOutStorageBlock, + CTLSStorageArray *psaListSegmentBegin, CTLSStorageArray *psaListSegmentEnd) +{ + OU_ASSERT(psaListSegmentBegin != psaListSegmentEnd); + + bool bResult; + + CTLSStorageArray *psaListSegmentCurrent = psaListSegmentBegin; + + while (true) + { + if (FindFreeStorageBlockFromArray(psbOutStorageBlock, psaListSegmentCurrent)) + { + bResult = true; + break; + } + + psaListSegmentCurrent = psaListSegmentCurrent->GetNextArray(); + + if (psaListSegmentCurrent == psaListSegmentEnd) + { + bResult = false; + break; + } + } + + return bResult; +} + +bool CTLSStorageInstance::FindFreeStorageBlockFromArray(CTLSStorageBlock *&psbOutStorageBlock, + CTLSStorageArray *psaArrayInstance) +{ + tlsindextype iValueCount = GetValueCount(); + bool bIsManualCleanup = GetThreadManualCleanupFlag(); + + return psaArrayInstance->FindFreeStorageBlock(psbOutStorageBlock, iValueCount, bIsManualCleanup); +} + + +void CTLSStorageInstance::AddStorageArrayToArrayList(CTLSStorageArray *psaStorageArray) +{ + while (true) + { + CTLSStorageArray *psaListCurrentHead = GetStorageArrayList(); + psaStorageArray->SetNextArray(psaListCurrentHead); + + if (TrySettingStorageArrayList(psaStorageArray, psaListCurrentHead)) + { + break; + } + } +} + + +bool CTLSStorageInstance::AllocateStorageKey(HTLSKEYVALUE &hkvOutStorageKey, ESTORAGEINSTANCEKIND ikInstanceKind) +{ + bool bResult = false; + +#if _OU_TARGET_OS == _OU_TARGET_OS_WINDOWS + + DWORD dwTlsIndex = ::TlsAlloc(); + + if (dwTlsIndex != TLS_OUT_OF_INDEXES) + { + hkvOutStorageKey = (HTLSKEYVALUE)(HTLSKEYVALUE::value_type)(size_t)dwTlsIndex; + bResult = true; + } + + +#else // #if _OU_TARGET_OS != _OU_TARGET_OS_WINDOWS + + pthread_key_t pkThreadKey; + + int iKeyCreationResult = pthread_key_create(&pkThreadKey, + (ikInstanceKind == SIK_AUTOCLEANUP) ? &CTLSStorageInstance::FreeStorageBlock_Callback_Automatic : &CTLSStorageInstance::FreeStorageBlock_Callback_Manual); + if (iKeyCreationResult == EOK) + { + hkvOutStorageKey = (HTLSKEYVALUE)(HTLSKEYVALUE::value_type)(size_t)pkThreadKey; + bResult = true; + } + + +#endif // #if _OU_TARGET_OS == ... + + return bResult; +} + +void CTLSStorageInstance::FreeStorageKey(const HTLSKEYVALUE &hkvStorageKey) +{ +#if _OU_TARGET_OS == _OU_TARGET_OS_WINDOWS + + DWORD dwTlsIndex = (DWORD)(size_t)(HTLSKEYVALUE::value_type)hkvStorageKey; + OU_ASSERT(dwTlsIndex != TLS_OUT_OF_INDEXES); + + BOOL bIndexFreeingResult = ::TlsFree(dwTlsIndex); + OU_VERIFY(bIndexFreeingResult); + + +#else // #if _OU_TARGET_OS != _OU_TARGET_OS_WINDOWS + + pthread_key_t pkThreadKey = (pthread_key_t)(size_t)(HTLSKEYVALUE::value_type)hkvStorageKey; + + int iKeyDeletionResult = pthread_key_delete(pkThreadKey); + OU_VERIFY(iKeyDeletionResult == EOK); + + +#endif // #if _OU_TARGET_OS == ... +} + + +#if _OU_TARGET_OS != _OU_TARGET_OS_WINDOWS + +void CTLSStorageInstance::FreeStorageBlock_Callback_Automatic(void *pv_DataValue) +{ + if (pv_DataValue) // Just a precaution + { + CTLSStorageBlock *psbStorageBlock = (CTLSStorageBlock *)pv_DataValue; + + g_apsiStorageGlobalInstances[SIK_AUTOCLEANUP]->FreeStorageBlock(psbStorageBlock); + } +} + +void CTLSStorageInstance::FreeStorageBlock_Callback_Manual(void *pv_DataValue) +{ + if (pv_DataValue) // Just a precaution + { + CTLSStorageBlock *psbStorageBlock = (CTLSStorageBlock *)pv_DataValue; + + g_apsiStorageGlobalInstances[SIK_MANUALCLEANUP]->FreeStorageBlock(psbStorageBlock); + } +} + + +#endif // #if _OU_TARGET_OS != _OU_TARGET_OS_WINDOWS + + +void CTLSStorageInstance::FreeStorageBlock(CTLSStorageBlock *psbStorageBlock) +{ + const int iValueCount = GetValueCount(); + + CTLSStorageArray *psaArrayInstance = psbStorageBlock->GetHostArray(); + psaArrayInstance->FreeStorageBlockOnThreadExit(psbStorageBlock, iValueCount); +} + + +CTLSStorageArray *CTLSStorageInstance::AllocateStorageArray() +{ + const tlsindextype iValueCount = GetValueCount(); + + return CTLSStorageArray::AllocateInstance(iValueCount); +} + +void CTLSStorageInstance::FreeStorageArrayList(CTLSStorageArray *psaStorageArrayList) +{ + const tlsindextype iValueCount = GetValueCount(); + + while (psaStorageArrayList) + { + CTLSStorageArray *psaStorageNextArray = psaStorageArrayList->GetNextArray(); + + psaStorageArrayList->FreeInstance(iValueCount); + + psaStorageArrayList = psaStorageNextArray; + } +} + + +////////////////////////////////////////////////////////////////////////// +// CThreadLocalStorage methods + +bool CThreadLocalStorage::AllocateAndSetStorageValue(const HTLSKEYSELECTOR &hksKeySelector, + tlsindextype iValueIndex, tlsvaluetype vValueData, CTLSValueDestructor fnValueDestructor) +{ + OU_ASSERT(OU_IN_SIZET_RANGE(DecodeInstanceKindFromKeySelector(hksKeySelector), SIK__MIN, SIK__MAX)); + + bool bResult = false; + + do + { + ESTORAGEINSTANCEKIND ikInstanceKind = (ESTORAGEINSTANCEKIND)DecodeInstanceKindFromKeySelector(hksKeySelector); + CTLSStorageInstance *psiStorageInstance = g_apsiStorageGlobalInstances[ikInstanceKind]; + + CTLSStorageBlock *psbStorageBlock; + + if (!psiStorageInstance->FindFreeStorageBlock(psbStorageBlock)) + { + break; + } + + SetKeyStorageBlock(hksKeySelector, psbStorageBlock); + + psbStorageBlock->SetValueData(iValueIndex, vValueData); + psbStorageBlock->SetValueDestructor(iValueIndex, fnValueDestructor); + + bResult = true; + } + while (false); + + return bResult; +} + + +////////////////////////////////////////////////////////////////////////// +// CTLSInitialization methods + +bool CTLSInitialization::InitializeTLSAPI(HTLSKEY &hskOutStorageKey, tlsindextype iValueCount, + unsigned int uiInitializationFlags/*=0*/) +{ + OU_ASSERT(g_uiThreadLocalStorageInitializationCount != 0U - 1U); + + bool bResult = false; + + bool bAtomicAPIInitialized = false; + + do + { + const ESTORAGEINSTANCEKIND ikInstanceKind = (uiInitializationFlags & SIF_MANUAL_CLEANUP_ON_THREAD_EXIT) ? SIK_MANUALCLEANUP : SIK_AUTOCLEANUP; + + if (g_apsiStorageGlobalInstances[ikInstanceKind] == NULL) // Initialization/finalization must be called from main thread + { + if (!InitializeAtomicAPI()) + { + break; + } + + bAtomicAPIInitialized = true; + + if (!InitializeTLSAPIValidated(ikInstanceKind, iValueCount, uiInitializationFlags)) + { + break; + } + + const HTLSKEYVALUE &hkvStorageKey = g_apsiStorageGlobalInstances[ikInstanceKind]->RetrieveStorageKey(); + g_ahkvStorageGlobalKeyValues[ikInstanceKind] = hkvStorageKey; + } + + ++g_uiThreadLocalStorageInitializationCount; + + hskOutStorageKey = EncodeKeySelectorFromStorageKind(ikInstanceKind); + OU_ASSERT(iValueCount == g_apsiStorageGlobalInstances[ikInstanceKind]->RetrieveValueCount()); + OU_ASSERT(uiInitializationFlags == g_apsiStorageGlobalInstances[ikInstanceKind]->RetrieveInitializationFlags()); + + bResult = true; + } + while (false); + + if (!bResult) + { + if (bAtomicAPIInitialized) + { + FinalizeAtomicAPI(); + } + } + + return bResult; +} + +void CTLSInitialization::FinalizeTLSAPI() +{ + OU_ASSERT(g_uiThreadLocalStorageInitializationCount != 0U); + + ESTORAGEINSTANCEKIND ikInstanceKind = + (--g_uiThreadLocalStorageInitializationCount == 0U) ? SIK__MIN : SIK__MAX; // Initialization/finalization must be called from main thread + for (; ikInstanceKind != SIK__MAX; ++ikInstanceKind) + { + if (g_apsiStorageGlobalInstances[ikInstanceKind]) + { + g_ahkvStorageGlobalKeyValues[ikInstanceKind] = 0; + + FinalizeTLSAPIValidated(ikInstanceKind); + + FinalizeAtomicAPI(); + } + } +} + + +void CTLSInitialization::CleanupOnThreadExit() +{ + const ESTORAGEINSTANCEKIND ikInstanceKind = SIK_MANUALCLEANUP; + CTLSStorageInstance *psiStorageInstance = g_apsiStorageGlobalInstances[ikInstanceKind]; + + if (psiStorageInstance != NULL) + { + OU_ASSERT(psiStorageInstance->GetIsThreadManualCleanup()); + + const HTLSKEYSELECTOR &hksKeySelector = EncodeKeySelectorFromStorageKind(ikInstanceKind); + CTLSStorageBlock *psbStorageBlock = CThreadLocalStorage::GetKeyStorageBlock(hksKeySelector); + + if (psbStorageBlock) + { + psiStorageInstance->FreeStorageBlockOnThreadExit(psbStorageBlock); + + CThreadLocalStorage::SetKeyStorageBlock(hksKeySelector, NULL); + } + } + else + { + OU_ASSERT(false); // The method is not supposed to be called if manual cleanup was not requested on initialization + } +} + + +bool CTLSInitialization::InitializeTLSAPIValidated(unsigned int uiInstanceKind, + tlsindextype iValueCount, unsigned int uiInitializationFlags) +{ + OU_ASSERT(g_apsiStorageGlobalInstances[uiInstanceKind] == NULL); + + bool bResult = false; + + CTLSStorageInstance *psiStorageInstance; + + do + { + // Use static methods instead of constructor/destructor + // to avoid overloading operators new/delete and for + // uniformity with CTLSStorageArray class + psiStorageInstance = CTLSStorageInstance::AllocateInstance(iValueCount, uiInitializationFlags); + + if (!psiStorageInstance) + { + break; + } + + if (!psiStorageInstance->Init((ESTORAGEINSTANCEKIND)uiInstanceKind)) + { + break; + } + + g_apsiStorageGlobalInstances[uiInstanceKind] = psiStorageInstance; + + bResult = true; + } + while (false); + + if (!bResult) + { + if (psiStorageInstance) + { + psiStorageInstance->FreeInstance(); + } + } + + return bResult; +} + +void CTLSInitialization::FinalizeTLSAPIValidated(unsigned int uiInstanceKind) +{ + OU_ASSERT(g_apsiStorageGlobalInstances[uiInstanceKind] != NULL); + + g_apsiStorageGlobalInstances[uiInstanceKind]->FreeInstance(); + g_apsiStorageGlobalInstances[uiInstanceKind] = NULL; +} + + +END_NAMESPACE_OU(); + + +#endif // #if _OU_FEATURE_SET >= _OU_FEATURE_SET_TLS + |