From 311b7f819ff5cc79b85de69620361d827cad215d Mon Sep 17 00:00:00 2001 From: "Brian J. Murrell" Date: Tue, 2 Apr 2024 16:05:30 -0400 Subject: [PATCH 01/12] Update to 1.2 Update packaging. Cease building on CentOS 7. Test with 'pr' tests. Skip-PR-comments: true Skip-list: test_daos_single_rdg_tx:DAOS-14982 Required-githooks: true Signed-off-by: Brian J. Murrell --- Jenkinsfile | 3 +- argobots.spec | 7 +++- debian/changelog | 6 +++ packaging/Dockerfile.centos.7 | 30 ++++++++++++-- packaging/Dockerfile.mockbuild | 30 +++++++++----- packaging/Makefile_distro_vars.mk | 8 ++++ packaging/Makefile_packaging.mk | 9 ++++- packaging/ccache-stats.patch | 66 +++++++++++++++++++++++++++++++ packaging/get_base_branch | 22 +++++++++++ packaging/rpm_chrootbuild | 57 ++++++++++++++++---------- 10 files changed, 199 insertions(+), 39 deletions(-) create mode 100644 packaging/ccache-stats.patch create mode 100755 packaging/get_base_branch diff --git a/Jenkinsfile b/Jenkinsfile index 20b4dcd6..b1ebbab6 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -41,4 +41,5 @@ //@Library(value="pipeline-lib@your_branch") _ /* groovylint-disable-next-line CompileStatic */ -packageBuildingPipelineDAOSTest(['distros' : ['centos7', 'el8', 'el9', 'leap15', 'ubuntu20.04']]) +packageBuildingPipelineDAOSTest(['distros' : ['el8', 'el9', 'leap15', 'ubuntu20.04',], + 'test-tag': 'pr']) diff --git a/argobots.spec b/argobots.spec index c8ea4354..a0f05145 100644 --- a/argobots.spec +++ b/argobots.spec @@ -1,12 +1,12 @@ Name: argobots %global major 1 -%global minor 1 +%global minor 2 #%%global prerelease %global tag %{major}.%{minor}%{?prerelease} Version: %{major}.%{minor}%{?prerelease:~%{prerelease}} -Release: 3%{?dist} +Release: 1%{?dist} Summary: Lightweight, low-level threading and tasking framework Group: System Environment/Libraries License: UChicago Argonne, LLC -- Argobots License @@ -109,6 +109,9 @@ rm -f %{buildroot}%{_libdir}/*.{l,}a %doc README %changelog +* Tue Apr 02 2024 Brian J. Murrell - 1.2-1 +- Update to 1.2 + * Tue Jun 06 2023 Brian J. Murrell - 1.1-3 - Update to build on EL9 diff --git a/debian/changelog b/debian/changelog index ba7e871e..27f06b66 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +argobots (1.2-1) unstable; urgency=medium + [ Brian J. Murrell ] + * Update to 1.2 + + -- Brian J. Murrell Tue, 02 Apr 2024 16:08:44 -0400 + argobots (1.1-2) unstable; urgency=medium [ Brian J. Murrell ] * NOOP change to keep parity with RPM versioning diff --git a/packaging/Dockerfile.centos.7 b/packaging/Dockerfile.centos.7 index cdfb7f69..189ea1e4 100644 --- a/packaging/Dockerfile.centos.7 +++ b/packaging/Dockerfile.centos.7 @@ -5,9 +5,31 @@ # # Pull base image -FROM centos:7 +FROM centos:centos7 LABEL maintainer="daos@daos.groups.io" +# Use local repo server if present +ARG REPO_FILE_URL +RUN set -e; \ + if [ -n "$REPO_FILE_URL" ]; then \ + cd /etc/yum.repos.d/ && \ + curl -k -f -o daos_ci-centos7-artifactory.repo.tmp \ + "$REPO_FILE_URL"daos_ci-centos7-artifactory.repo && \ + for file in *.repo; do \ + true > $file; \ + done; \ + mv daos_ci-centos7-artifactory.repo{.tmp,}; \ + fi; \ + yum -y install dnf; \ + yum clean all; \ + dnf --disablerepo \*epel\* -y install epel-release \ + dnf-plugins-core; \ + if [ -n "$REPO_FILE_URL" ]; then \ + dnf -y --quiet config-manager --disable epel; \ + fi; \ + dnf -y update epel-release; \ + dnf -y clean all + # use same UID as host and default value of 1000 if not specified ARG UID=1000 @@ -15,9 +37,9 @@ ARG UID=1000 #Nothing to do for CentOS # Install basic tools -RUN yum install -y epel-release -RUN yum install -y mock make rpm-build curl createrepo rpmlint redhat-lsb-core \ - git python-srpm-macros dnf +RUN dnf install -y epel-release +RUN dnf install -y mock make rpm-build curl createrepo rpmlint redhat-lsb-core \ + git python-srpm-macros dnf && dnf -y clean all # Add build user (to keep rpmbuild happy) ENV USER build diff --git a/packaging/Dockerfile.mockbuild b/packaging/Dockerfile.mockbuild index c8bc1a48..76a6e941 100644 --- a/packaging/Dockerfile.mockbuild +++ b/packaging/Dockerfile.mockbuild @@ -1,11 +1,11 @@ # -# Copyright 2018-2023 Intel Corporation +# Copyright 2018-2024 Intel Corporation # # 'recipe' for Docker to build an RPM # # Pull base image -ARG FVERSION=38 +ARG FVERSION=latest FROM fedora:$FVERSION # Needed for later use of FVERSION ARG FVERSION @@ -15,16 +15,19 @@ LABEL maintainer="daos@daos.groups.io" ARG REPO_FILE_URL RUN if [ -n "$REPO_FILE_URL" ]; then \ cd /etc/yum.repos.d/ && \ - curl -f -o daos_ci-fedora-artifactory.repo.tmp \ + curl -k -f -o daos_ci-fedora-artifactory.repo.tmp \ "$REPO_FILE_URL"daos_ci-fedora-artifactory.repo && \ - rm -f *.repo && \ + for file in *.repo; do \ + true > $file; \ + done; \ mv daos_ci-fedora-artifactory.repo{.tmp,}; \ fi # Install basic tools RUN dnf -y install mock make \ rpm-build createrepo rpmlint redhat-lsb-core git \ - python-srpm-macros rpmdevtools + python-srpm-macros rpmdevtools && \ + dnf -y clean all # use same UID as host and default value of 1000 if not specified ARG UID=1000 @@ -45,15 +48,24 @@ RUN dnf -y upgrade && \ # https://github.com/rpm-software-management/rpmlint/pull/795 in it # But make sure to patch after dnf upgrade so that an upgraded rpmlint # RPM doesn't wipe out our patch -COPY packaging/rpmlint--ignore-unused-rpmlintrc.patch . +# Ditto for the patch to zero and display ccache stats +# https://github.com/rpm-software-management/mock/pull/1299 +ARG PACKAGINGDIR=packaging +COPY ${PACKAGINGDIR}/*.patch ./ RUN (cd $(python3 -c 'import site; print(site.getsitepackages()[-1])') && \ if ! grep -e --ignore-unused-rpmlintrc rpmlint/cli.py; then \ - if ! patch -p1; then \ + if ! patch -p1 < $OLDPWD/rpmlint--ignore-unused-rpmlintrc.patch; then \ exit 1; \ fi; \ rm -f rpmlint/__pycache__/{cli,lint}.*.pyc; \ - fi) < rpmlint--ignore-unused-rpmlintrc.patch; \ - rm -f rpmlint--ignore-unused-rpmlintrc.patch + fi; \ + if ! grep _ccachePostBuildHook mockbuild/plugins/ccache.py; then \ + if ! patch -p3 < $OLDPWD/ccache-stats.patch; then \ + exit 1; \ + fi; \ + rm -f mockbuild/plugins/__pycache__/ccache.*.pyc; \ + fi); \ + rm -f rpmlint--ignore-unused-rpmlintrc.patch ccache-stats.patch # show the release that was built ARG CACHEBUST diff --git a/packaging/Makefile_distro_vars.mk b/packaging/Makefile_distro_vars.mk index 6a7f88b6..4e8a09dc 100644 --- a/packaging/Makefile_distro_vars.mk +++ b/packaging/Makefile_distro_vars.mk @@ -83,6 +83,14 @@ DISTRO_VERSION ?= $(VERSION_ID) ORIG_TARGET_VER := 15.4 SED_EXPR := 1p endif +ifeq ($(CHROOT_NAME),opensuse-leap-15.5-x86_64) +VERSION_ID := 15.5 +DISTRO_ID := sl15.5 +DISTRO_BASE := LEAP_15 +DISTRO_VERSION ?= $(VERSION_ID) +ORIG_TARGET_VER := 15.5 +SED_EXPR := 1p +endif endif ifeq ($(ID),centos) ID = el diff --git a/packaging/Makefile_packaging.mk b/packaging/Makefile_packaging.mk index 6f4b16fe..3201a227 100644 --- a/packaging/Makefile_packaging.mk +++ b/packaging/Makefile_packaging.mk @@ -54,6 +54,7 @@ RPM_BUILD_OPTIONS := $(BUILD_DEFINES) GIT_DIFF_EXCLUDES := $(PATCH_EXCLUDE_FILES:%=':!%') endif +FVERSION ?= latest COMMON_RPM_ARGS := --define "_topdir $$PWD/_topdir" $(BUILD_DEFINES) SPEC := $(shell if [ -f $(NAME)-$(DISTRO_BASE).spec ]; then echo $(NAME)-$(DISTRO_BASE).spec; else echo $(NAME).spec; fi) VERSION = $(eval VERSION := $(shell rpm $(COMMON_RPM_ARGS) --specfile --qf '%{version}\n' $(SPEC) | sed -n '1p'))$(VERSION) @@ -163,7 +164,7 @@ endif $(notdir $(SOURCE) $(OTHER_SOURCES) $(REAL_SOURCE)): $(SPEC) $(CALLING_MAKEFILE) # TODO: need to clean up old ones - $(SPECTOOL) -g $(SPEC) + $(SPECTOOL) $(COMMON_RPM_ARGS) -g $(SPEC) $(DEB_TOP)/%: % | $(DEB_TOP)/ @@ -363,12 +364,14 @@ chrootbuild: $(SRPM) $(CALLING_MAKEFILE) LOCAL_REPOS='$(LOCAL_REPOS)' \ ARTIFACTORY_URL="$(ARTIFACTORY_URL)" \ DISTRO_VERSION="$(DISTRO_VERSION)" \ + PACKAGE="$(NAME)" \ TARGET="$<" \ packaging/rpm_chrootbuild endif podman_chrootbuild: if ! podman build --build-arg REPO_FILE_URL=$(REPO_FILE_URL) \ + --build-arg FVERSION=$(FVERSION) \ -t $(subst +,-,$(CHROOT_NAME))-chrootbuild \ -f packaging/Dockerfile.mockbuild .; then \ echo "Container build failed"; \ @@ -386,7 +389,9 @@ podman_chrootbuild: exit 1; \ fi; \ rpmlint $$(ls /var/lib/mock/$(CHROOT_NAME)/result/*.rpm | \ - grep -v -e debuginfo -e debugsource -e src.rpm)' + grep -v -e debuginfo -e debugsource -e src.rpm)'; then \ + exit 1; \ + fi docker_chrootbuild: if ! $(DOCKER) build --build-arg UID=$$(id -u) -t chrootbuild \ diff --git a/packaging/ccache-stats.patch b/packaging/ccache-stats.patch new file mode 100644 index 00000000..26d5eeb7 --- /dev/null +++ b/packaging/ccache-stats.patch @@ -0,0 +1,66 @@ +From e87d916d7f49ea4949973adf0f09e9e5bf891e03 Mon Sep 17 00:00:00 2001 +From: "Brian J. Murrell" +Date: Tue, 30 Jan 2024 11:03:12 -0500 +Subject: [PATCH 1/2] Show ccache stats at the end of the build + +Zero the ccache stats at the beginning of the build and then display the +ccache stats at the end of the build to see how effective ccache was. + +Signed-off-by: Brian J. Murrell +--- + mock/py/mockbuild/plugins/ccache.py | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/mock/py/mockbuild/plugins/ccache.py b/mock/py/mockbuild/plugins/ccache.py +index 2666ad9fc..1080ffe68 100644 +--- a/mock/py/mockbuild/plugins/ccache.py ++++ b/mock/py/mockbuild/plugins/ccache.py +@@ -35,6 +35,7 @@ def __init__(self, plugins, conf, buildroot): + buildroot.preexisting_deps.append("ccache") + plugins.add_hook("prebuild", self._ccacheBuildHook) + plugins.add_hook("preinit", self._ccachePreInitHook) ++ plugins.add_hook("postbuild", self._ccachePostBuildHook) + buildroot.mounts.add( + BindMountPoint(srcpath=self.ccachePath, bindpath=buildroot.make_chroot_path("/var/tmp/ccache"))) + +@@ -47,6 +48,9 @@ def __init__(self, plugins, conf, buildroot): + @traceLog() + def _ccacheBuildHook(self): + self.buildroot.doChroot(["ccache", "-M", str(self.ccache_opts['max_cache_size'])], shell=False) ++ # zero ccache stats ++ getLog().info("Zero ccache stats:") ++ self.buildroot.doChroot(["ccache", "--zero-stats"], printOutput=True, shell=False) + + # set up the ccache dir. + # we also set a few variables used by ccache to find the shared cache. +@@ -61,3 +65,10 @@ def _ccachePreInitHook(self): + file_util.mkdirIfAbsent(self.buildroot.make_chroot_path('/var/tmp/ccache')) + file_util.mkdirIfAbsent(self.ccachePath) + self.buildroot.uid_manager.changeOwner(self.ccachePath, recursive=True) ++ ++ # get some cache stats ++ def _ccachePostBuildHook(self): ++ # show the cache hit stats ++ getLog().info("ccache stats:") ++ self.buildroot.doChroot(["ccache", "--show-stats"], printOutput=True, shell=False) +++ + +From bfd3a7e1bb47d28ee60a94cb5985c1f66476475f Mon Sep 17 00:00:00 2001 +From: "Brian J. Murrell" +Date: Tue, 30 Jan 2024 11:17:48 -0500 +Subject: [PATCH 2/2] Remove extraneous line + +Signed-off-by: Brian J. Murrell +--- + mock/py/mockbuild/plugins/ccache.py | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/mock/py/mockbuild/plugins/ccache.py b/mock/py/mockbuild/plugins/ccache.py +index 1080ffe68..1a20846d3 100644 +--- a/mock/py/mockbuild/plugins/ccache.py ++++ b/mock/py/mockbuild/plugins/ccache.py +@@ -71,4 +71,3 @@ def _ccachePostBuildHook(self): + # show the cache hit stats + getLog().info("ccache stats:") + self.buildroot.doChroot(["ccache", "--show-stats"], printOutput=True, shell=False) +-+ diff --git a/packaging/get_base_branch b/packaging/get_base_branch new file mode 100755 index 00000000..27515a71 --- /dev/null +++ b/packaging/get_base_branch @@ -0,0 +1,22 @@ +#!/bin/bash + +# find the base branch of the current branch + +set -eux -o pipefail +IFS=' ' read -r -a add_bases <<< "${1:-}" +origin=origin +mapfile -t all_bases < <(echo "master" + git branch -r | sed -ne "/^ $origin\\/release\\/[0-9]/s/^ $origin\\///p") +all_bases+=("${add_bases[@]}") +TARGET="master" +min_diff=-1 +for base in "${all_bases[@]}"; do + git rev-parse --verify "$origin/$base" &> /dev/null || continue + commits_ahead=$(git log --oneline "$origin/$base..HEAD" | wc -l) + if [ "$min_diff" -eq -1 ] || [ "$min_diff" -gt "$commits_ahead" ]; then + TARGET="$base" + min_diff=$commits_ahead + fi +done +echo "$TARGET" +exit 0 diff --git a/packaging/rpm_chrootbuild b/packaging/rpm_chrootbuild index d122e0e2..4dcdaa4b 100755 --- a/packaging/rpm_chrootbuild +++ b/packaging/rpm_chrootbuild @@ -2,10 +2,14 @@ set -uex -original_cfg_file="/etc/mock/$CHROOT_NAME.cfg" -cfg_file=mock.cfg +cp /etc/mock/"$CHROOT_NAME".cfg mock.cfg + +# Enable mock ccache plugin +cat <> mock.cfg +config_opts['plugin_conf']['ccache_enable'] = True +config_opts['plugin_conf']['ccache_opts']['dir'] = "%(cache_topdir)s/%(root)s/ccache/" +EOF -cp "$original_cfg_file" "$cfg_file" if [[ $CHROOT_NAME == *epel-8-x86_64 ]]; then cat <> mock.cfg @@ -22,7 +26,7 @@ if [[ $CHROOT_NAME == *epel-7-x86_64 ]]; then fi # Allow BR: foo-devel < 1.2 to work when foo-devel-1.3 is actually available -cat <> "$cfg_file" +cat <> mock.cfg config_opts['dnf.conf'] += """ [main] best=0 @@ -33,7 +37,7 @@ EOF repo_adds=() repo_dels=() -echo -e "config_opts['yum.conf'] += \"\"\"\n" >> "$cfg_file" +echo -e "config_opts['yum.conf'] += \"\"\"\n" >> mock.cfg if [ -n "${ARTIFACTORY_URL:-}" ] && "$LOCAL_REPOS"; then repo_dels+=("--disablerepo=\*") @@ -56,7 +60,7 @@ if [ -n "${ARTIFACTORY_URL:-}" ] && "$LOCAL_REPOS"; then REPO_FILE_URL="file://$(readlink -e "$REPO_FILES_PR")/" fi fi - curl -sSf "${REPO_FILE_URL}daos_ci-$DISTRO"-mock-artifactory.repo >> "$cfg_file" + curl -sSf "$REPO_FILE_URL"daos_ci-"${CHROOT_NAME%-*}".repo >> mock.cfg repo_adds+=("--enablerepo *-artifactory") fi fi @@ -81,9 +85,9 @@ for repo in $DISTRO_BASE_PR_REPOS $PR_REPOS; do repo_adds+=("--enablerepo $repo:${branch//[@\/]/_}:$build_number") echo -e "[$repo:${branch//[@\/]/_}:$build_number]\n\ name=$repo:${branch//[@\/]/_}:$build_number\n\ -baseurl=${JENKINS_URL:-https://build.hpdd.intel.com/}job/daos-stack/job/$repo/job/${branch//\//%2F}/$build_number/artifact/artifacts/$DISTRO/\n\ +baseurl=${ARTIFACTS_URL:-${JENKINS_URL:-https://build.hpdd.intel.com/}job/}daos-stack/job/$repo/job/${branch//\//%2F}/$build_number/artifact/artifacts/$DISTRO/\n\ enabled=1\n\ -gpgcheck=False\n" >> "$cfg_file" +gpgcheck=False\n" >> mock.cfg done for repo in $JOB_REPOS; do repo_name=${repo##*://} @@ -97,29 +101,40 @@ for repo in $JOB_REPOS; do echo -e "[${repo_name//[@\/]/_}]\n\ name=${repo_name}\n\ baseurl=${repo//\//%2F}\n\ -enabled=1\n" >> "$cfg_file" +enabled=1\n" >> mock.cfg done -echo "\"\"\"" >> "$cfg_file" +echo "\"\"\"" >> mock.cfg if [ -n "$DISTRO_VERSION" ]; then releasever_opt=("--config-opts=releasever=$DISTRO_VERSION") fi bs_dir=/scratch/mock/cache/"${CHROOT_NAME}"-bootstrap -if ls -l /scratch/mock/cache/"${CHROOT_NAME}"-bootstrap/root_cache/cache.tar.gz; then - mkdir -p "/var/cache/mock/${CHROOT_NAME}-bootstrap" +if ls -l "$bs_dir"/root_cache/cache.tar.gz; then + mkdir -p "/var/cache/mock/${CHROOT_NAME}-bootstrap/" flock "$bs_dir" -c "cp -a $bs_dir/root_cache /var/cache/mock/${CHROOT_NAME}-bootstrap" fi +if ls -l "$bs_dir/ccache-$CHROOT_NAME-$PACKAGE".tar.gz; then + flock "$bs_dir" -c "tar -C / -xzf $bs_dir/ccache-$CHROOT_NAME-$PACKAGE.tar.gz" +fi -# shellcheck disable=SC2086 -eval mock -r "$cfg_file" ${repo_dels[*]} ${repo_adds[*]} --disablerepo=\*-debug* \ - "${releasever_opt[@]}" $MOCK_OPTIONS $RPM_BUILD_OPTIONS "$TARGET" +rc=0 +# shellcheck disable=SC2086,SC2048 +if ! eval time mock -r mock.cfg ${repo_dels[*]} ${repo_adds[*]} --no-clean \ + --disablerepo=\*-debug* ${releasever_opt[*]} $MOCK_OPTIONS \ + $RPM_BUILD_OPTIONS "$TARGET"; then + rc=${PIPESTATUS[0]} +fi -date -if ls -l /var/cache/mock/"${CHROOT_NAME}"-bootstrap/root_cache/cache.tar.gz && - [ -d /scratch/ ]; then - mkdir -p /scratch/mock/cache/"${CHROOT_NAME}"-bootstrap/ - if ! cmp /var/cache/mock/"${CHROOT_NAME}"-bootstrap/root_cache/cache.tar.gz "$bs_dir"/root_cache/cache.tar.gz; then - flock "$bs_dir" -c "cp -a /var/cache/mock/${CHROOT_NAME}-bootstrap/root_cache $bs_dir/" +# Save the ccache +if [ -d /scratch/ ]; then + mkdir -p "$bs_dir"/ + flock "$bs_dir" -c "tar -czf $bs_dir/ccache-$CHROOT_NAME-$PACKAGE.tar.gz /var/cache/mock/${CHROOT_NAME}/ccache" + if ls -l /var/cache/mock/"${CHROOT_NAME}"-bootstrap/root_cache/cache.tar.gz; then + if ! cmp /var/cache/mock/"${CHROOT_NAME}"-bootstrap/root_cache/cache.tar.gz "$bs_dir"/root_cache/cache.tar.gz; then + flock "$bs_dir" -c "cp -a /var/cache/mock/${CHROOT_NAME}-bootstrap/root_cache $bs_dir/" + fi fi fi + +exit "$rc" From b6db3dba00c0d52ce5094d0e7168d271b89aaec0 Mon Sep 17 00:00:00 2001 From: "Brian J. Murrell" Date: Tue, 11 Jun 2024 08:33:10 -0400 Subject: [PATCH 02/12] Update packaging/ Skip-PR-comments: true Skip-list: test_daos_single_rdg_tx:DAOS-14982 Required-githooks: true Signed-off-by: Brian J. Murrell --- packaging/Dockerfile.ubuntu.20.04 | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/packaging/Dockerfile.ubuntu.20.04 b/packaging/Dockerfile.ubuntu.20.04 index ec76bfd1..4d054644 100644 --- a/packaging/Dockerfile.ubuntu.20.04 +++ b/packaging/Dockerfile.ubuntu.20.04 @@ -18,26 +18,23 @@ RUN if [ -n "$REPO_FILE_URL" ]; then \ true > ../sources.list && \ mv daos_ci-ubuntu20.04-artifactory.list.tmp \ daos_ci-ubuntu20.04-artifactory.list; \ + url="${REPO_FILE_URL%/*/}/hpe-ilorest-ubuntu-bionic-proxy/"; \ + else \ + url="https://downloads.linux.hpe.com/SDR/repo/ilorest/"; \ fi; \ cd -; \ - curl -f -O "$REPO_FILE_URL"esad_repo.key; \ - gpg --no-default-keyring --keyring ./temp-keyring.gpg \ - --import esad_repo.key; \ mkdir -p /usr/local/share/keyrings/; \ + curl -f -O "$url"GPG-KEY-hprest; \ + gpg --no-default-keyring --keyring ./temp-keyring.gpg \ + --import GPG-KEY-hprest; \ gpg --no-default-keyring --keyring ./temp-keyring.gpg --export \ - --output /usr/local/share/keyrings/daos-stack-public.gpg; \ + --output /usr/local/share/keyrings/hpe-sdr-public.gpg; \ rm ./temp-keyring.gpg; \ - url_prefix=https://downloads.linux.hpe.com/SDR/; \ - for url in hpPublicKey2048.pub \ - hpPublicKey2048_key1.pub \ - hpePublicKey2048_key1.pub; do \ - curl -f -O "$url_prefix$url"; \ - gpg --no-default-keyring --keyring ./temp-keyring.gpg \ - --import "$(basename $url)"; \ - done; \ + curl -f -O "$REPO_FILE_URL"esad_repo.key; \ + gpg --no-default-keyring --keyring ./temp-keyring.gpg \ + --import esad_repo.key; \ gpg --no-default-keyring --keyring ./temp-keyring.gpg --export \ - --output /usr/local/share/keyrings/hpe-sdr-public.gpg; \ - rm ./temp-keyring.gpg + --output /usr/local/share/keyrings/daos-stack-public.gpg # Install basic tools RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y \ From f446646d5100ad7745d05c1060122cf64288457f Mon Sep 17 00:00:00 2001 From: Cedric Koch-Hofer Date: Fri, 23 Aug 2024 08:57:17 +0000 Subject: [PATCH 03/12] DAOS-15596 pkg: Update Argobots to 1.2 Update packaging/ Add patch 411e5b3 remove deprecated patch 7fd1987 Signed-off-by: Cedric Koch-Hofer --- ...5b344642ebc82190fd8b125db512e5b449d1.patch | 14 + argobots.spec | 1 + debian/changelog | 1 + packaging/Dockerfile.mockbuild | 8 +- packaging/Makefile_packaging.mk | 6 + packaging/rpm_chrootbuild | 12 +- v1.1a1..7fd1987.patch | 6636 ----------------- 7 files changed, 36 insertions(+), 6642 deletions(-) create mode 100644 1.2..411e5b344642ebc82190fd8b125db512e5b449d1.patch delete mode 100644 v1.1a1..7fd1987.patch diff --git a/1.2..411e5b344642ebc82190fd8b125db512e5b449d1.patch b/1.2..411e5b344642ebc82190fd8b125db512e5b449d1.patch new file mode 100644 index 00000000..2da6357f --- /dev/null +++ b/1.2..411e5b344642ebc82190fd8b125db512e5b449d1.patch @@ -0,0 +1,14 @@ +diff --git a/src/info.c b/src/info.c +index 4127edf..5e5bb4b 100644 +--- a/src/info.c ++++ b/src/info.c +@@ -1097,7 +1097,8 @@ void ABTI_info_check_print_all_thread_stacks(void) + + /* Decrement the barrier value. */ + int dec_value = ABTD_atomic_fetch_sub_int(&print_stack_barrier, 1); +- if (dec_value == 0) { ++ /* previous value should be 1 ! */ ++ if (dec_value == 1) { + /* The last execution stream resets the flag. */ + ABTD_atomic_release_store_int(&print_stack_flag, + PRINT_STACK_FLAG_UNSET); diff --git a/argobots.spec b/argobots.spec index a0f05145..ac0155f8 100644 --- a/argobots.spec +++ b/argobots.spec @@ -111,6 +111,7 @@ rm -f %{buildroot}%{_libdir}/*.{l,}a %changelog * Tue Apr 02 2024 Brian J. Murrell - 1.2-1 - Update to 1.2 +- Add patch 411e5b3 fixing DAOS-14248 * Tue Jun 06 2023 Brian J. Murrell - 1.1-3 - Update to build on EL9 diff --git a/debian/changelog b/debian/changelog index 27f06b66..158fdb62 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,6 +1,7 @@ argobots (1.2-1) unstable; urgency=medium [ Brian J. Murrell ] * Update to 1.2 + * Add patch 411e5b3 fixing DAOS-14248 -- Brian J. Murrell Tue, 02 Apr 2024 16:08:44 -0400 diff --git a/packaging/Dockerfile.mockbuild b/packaging/Dockerfile.mockbuild index 76a6e941..6bad37d4 100644 --- a/packaging/Dockerfile.mockbuild +++ b/packaging/Dockerfile.mockbuild @@ -35,10 +35,12 @@ ARG UID=1000 # Add build user (to keep rpmbuild happy) ENV USER build ENV PASSWD build -RUN useradd -u $UID -ms /bin/bash $USER -RUN echo "$USER:$PASSWD" | chpasswd # add the user to the mock group so it can run mock -RUN usermod -a -G mock $USER +RUN if [ $UID != 0 ]; then \ + useradd -u $UID -ms /bin/bash $USER; \ + echo "$USER:$PASSWD" | chpasswd; \ + usermod -a -G mock $USER; \ + fi ARG CB0 RUN dnf -y upgrade && \ diff --git a/packaging/Makefile_packaging.mk b/packaging/Makefile_packaging.mk index 3201a227..75038c11 100644 --- a/packaging/Makefile_packaging.mk +++ b/packaging/Makefile_packaging.mk @@ -35,7 +35,11 @@ TEST_PACKAGES ?= ${NAME} # unfortunately we cannot always name the repo the same as the project REPO_NAME ?= $(NAME) +ifneq ($(CI_PR_REPOS),) +PR_REPOS ?= $(CI_PR_REPOS) +else PR_REPOS ?= $(shell git show -s --format=%B | sed -ne 's/^PR-repos: *\(.*\)/\1/p') +endif LEAP_15_PR_REPOS ?= $(shell git show -s --format=%B | sed -ne 's/^PR-repos-leap15: *\(.*\)/\1/p') EL_7_PR_REPOS ?= $(shell git show -s --format=%B | sed -ne 's/^PR-repos-el7: *\(.*\)/\1/p') EL_8_PR_REPOS ?= $(shell git show -s --format=%B | sed -ne 's/^PR-repos-el8: *\(.*\)/\1/p') @@ -424,6 +428,8 @@ packaging_check: --exclude libfabric.spec \ --exclude Makefile \ --exclude README.md \ + --exclude SECURITY.md \ + --exclude LICENSE \ --exclude _topdir \ --exclude \*.tar.\* \ --exclude \*.code-workspace \ diff --git a/packaging/rpm_chrootbuild b/packaging/rpm_chrootbuild index 4dcdaa4b..d6443b73 100755 --- a/packaging/rpm_chrootbuild +++ b/packaging/rpm_chrootbuild @@ -109,7 +109,7 @@ if [ -n "$DISTRO_VERSION" ]; then releasever_opt=("--config-opts=releasever=$DISTRO_VERSION") fi -bs_dir=/scratch/mock/cache/"${CHROOT_NAME}"-bootstrap +bs_dir=/scratch/mock/cache/"${CHROOT_NAME}"-bootstrap-$(id -u) if ls -l "$bs_dir"/root_cache/cache.tar.gz; then mkdir -p "/var/cache/mock/${CHROOT_NAME}-bootstrap/" flock "$bs_dir" -c "cp -a $bs_dir/root_cache /var/cache/mock/${CHROOT_NAME}-bootstrap" @@ -129,10 +129,16 @@ fi # Save the ccache if [ -d /scratch/ ]; then mkdir -p "$bs_dir"/ - flock "$bs_dir" -c "tar -czf $bs_dir/ccache-$CHROOT_NAME-$PACKAGE.tar.gz /var/cache/mock/${CHROOT_NAME}/ccache" + if ! flock "$bs_dir" -c "tar -czf $bs_dir/ccache-$CHROOT_NAME-$PACKAGE.tar.gz /var/cache/mock/${CHROOT_NAME}/ccache"; then + echo "Failed to save ccache. Plowing onward." + echo "I am $(id)" + fi if ls -l /var/cache/mock/"${CHROOT_NAME}"-bootstrap/root_cache/cache.tar.gz; then if ! cmp /var/cache/mock/"${CHROOT_NAME}"-bootstrap/root_cache/cache.tar.gz "$bs_dir"/root_cache/cache.tar.gz; then - flock "$bs_dir" -c "cp -a /var/cache/mock/${CHROOT_NAME}-bootstrap/root_cache $bs_dir/" + if ! flock "$bs_dir" -c "cp -a /var/cache/mock/${CHROOT_NAME}-bootstrap/root_cache $bs_dir/"; then + echo "Failed to save root_cache. Plowing onward." + echo "I am $(id)" + fi fi fi fi diff --git a/v1.1a1..7fd1987.patch b/v1.1a1..7fd1987.patch deleted file mode 100644 index 985bb10b..00000000 --- a/v1.1a1..7fd1987.patch +++ /dev/null @@ -1,6636 +0,0 @@ -diff --git a/configure.ac b/configure.ac -index ab324aa..6252c5c 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -222,6 +222,16 @@ AC_ARG_WITH([hugetlbfs], - AS_HELP_STRING([--with-hugetlbfs=PATH], - [specify path where hugetlbfs include directory and lib directory can be found])) - -+# --with-libunwind -+AC_ARG_WITH([libunwind], -+ AS_HELP_STRING([--with-libunwind=PATH], -+ [specify path where libunwind include directory and lib directory can be found])) -+ -+# --enable-stack-unwind -+AC_ARG_ENABLE([stack-unwind], -+ AS_HELP_STRING([--enable-stack-unwind], -+ [enable stack unwinding, which is disabled by default.])) -+ - # --with-papi - AC_ARG_WITH([papi], - AS_HELP_STRING([--with-papi=PATH], -@@ -730,6 +740,23 @@ if test "x$with_hugetlbfs" != "x"; then - AC_CHECK_LIB(hugetlbfs, get_huge_pages) - fi - -+# --enable-stack-unwind -+if test "x$enable_stack_unwind" = "xyes"; then -+ # --with-libunwind -+ if test "x$with_libunwind" != "x"; then -+ PAC_PREPEND_FLAG([-I${with_libunwind}/include], [CFLAGS]) -+ PAC_PREPEND_FLAG([-Wl,-rpath,${with_libunwind}/lib -L${with_libunwind}/lib], [LDFLAGS]) -+ fi -+ AC_CHECK_HEADERS(libunwind.h) -+ AC_CHECK_LIB(unwind, unw_backtrace) -+ if test x"$ac_cv_header_libunwind_h" = x"yes" -a x"$ac_cv_lib_unwind_unw_backtrace" = x"yes" ; then -+ AC_DEFINE(ABT_CONFIG_ENABLE_STACK_UNWIND, 1, [Define to use the stack unwinding feature.]) -+ PAC_PREPEND_FLAG([-lunwind], [LDFLAGS]) -+ else -+ AC_MSG_ERROR([libunwind is not found. Either remove --enable-stack-unwind or \ -+set --with-libunwind=LIBUNWIND_PREFIX_PATH.]) -+ fi -+fi - - # --with-papi - PAPI_CFLAGS="" -diff --git a/examples/profiling/abtx_prof.h b/examples/profiling/abtx_prof.h -index ce7f929..3a4bd7d 100644 ---- a/examples/profiling/abtx_prof.h -+++ b/examples/profiling/abtx_prof.h -@@ -132,8 +132,13 @@ static int ABTX_prof_finalize(ABTX_prof_context context); - */ - - #ifndef ABTX_PROF_USE_BUILTIN_EXPECT -+#if defined(__SUNPRO_C) && __SUNPRO_C < 0x5150 -+/* Solaris Studio <= 12.5 (Sun C 5.14) does not support __builtin_expect() */ -+#define ABTX_PROF_USE_BUILTIN_EXPECT 0 -+#else - #define ABTX_PROF_USE_BUILTIN_EXPECT 1 - #endif -+#endif /* ABTX_PROF_USE_BUILTIN_EXPECT */ - - #ifndef ABTX_PROF_USE_ALWAYS_INLINE - #define ABTX_PROF_USE_ALWAYS_INLINE 1 -@@ -233,7 +238,7 @@ static inline uint64_t ABTXI_prof_get_cycles() - #ifdef ABTXI_PROF_USE_CYCLES - - #define ABTXI_PROF_T int64_t --#define ABTXI_PROF_T_INVALID 0xFFFFFFFFFFFFFFFF -+#define ABTXI_PROF_T_INVALID ((int64_t)0xFFFFFFFFFFFFFFFF) - #define ABTXI_PROF_T_ZERO ((int64_t)0) - #define ABTXI_prof_get_time() ABTXI_prof_get_cycles() - #define ABTXI_PROF_T_STRING "HW cycles" -@@ -858,7 +863,7 @@ static char *ABTXI_prof_sprintf(ABTXI_prof_str_mem *p_str, size_t max_n, - while (p_str->p_next) { - p_str = p_str->p_next; - } -- if (p_str->len - p_str->cursor < max_n) { -+ if (p_str->len - p_str->cursor < (int)max_n) { - int newlen = max_n > 4096 ? max_n : 4096; - ABTXI_prof_str_mem *p_new = ABTXI_prof_str_mem_alloc(newlen); - p_str->p_next = p_new; -diff --git a/src/Makefile.am b/src/Makefile.am -index 09811d5..5420587 100644 ---- a/src/Makefile.am -+++ b/src/Makefile.am -@@ -26,8 +26,7 @@ abt_sources = \ - timer.c \ - tool.c \ - unit.c \ -- ythread.c \ -- ythread_htable.c -+ ythread.c - - include $(top_srcdir)/src/arch/Makefile.mk - include $(top_srcdir)/src/mem/Makefile.mk -diff --git a/src/arch/abtd_affinity.c b/src/arch/abtd_affinity.c -index 7fd9f5c..61e1242 100644 ---- a/src/arch/abtd_affinity.c -+++ b/src/arch/abtd_affinity.c -@@ -183,7 +183,7 @@ typedef cpuset_t cpu_set_t; - - typedef struct { - ABTD_affinity_cpuset initial_cpuset; -- size_t num_cpusets; -+ uint32_t num_cpusets; - ABTD_affinity_cpuset *cpusets; - } global_affinity; - -@@ -194,8 +194,9 @@ static inline int int_rem(int a, unsigned int b) - /* Return x where a = n * b + x and 0 <= x < b */ - /* Because of ambiguity in the C specification, it uses a branch to check if - * the result is positive. */ -- int ret = (a % b) + b; -- return ret >= b ? (ret - b) : ret; -+ int int_b = b; -+ int ret = (a % int_b) + int_b; -+ return ret >= int_b ? (ret - int_b) : ret; - } - - ABTU_ret_err static int get_num_cores(pthread_t native_thread, int *p_num_cores) -@@ -249,7 +250,7 @@ ABTU_ret_err static int apply_cpuset(pthread_t native_thread, - const ABTD_affinity_cpuset *p_cpuset) - { - #ifdef HAVE_PTHREAD_SETAFFINITY_NP -- size_t i; -+ uint32_t i; - cpu_set_t cpuset; - CPU_ZERO(&cpuset); - for (i = 0; i < p_cpuset->num_cpuids; i++) { -@@ -268,7 +269,8 @@ void ABTD_affinity_init(const char *affinity_str) - g_affinity.cpusets = NULL; - g_affinity.initial_cpuset.cpuids = NULL; - pthread_t self_native_thread = pthread_self(); -- int i, ret; -+ uint32_t i; -+ int ret; - ret = get_num_cores(self_native_thread, &gp_ABTI_global->num_cores); - if (ret != ABT_SUCCESS || gp_ABTI_global->num_cores == 0) { - gp_ABTI_global->set_affinity = ABT_FALSE; -@@ -299,7 +301,7 @@ void ABTD_affinity_init(const char *affinity_str) - ABTI_ASSERT(ret == ABT_SUCCESS); - for (i = 0; i < p_list->num; i++) { - const ABTD_affinity_id_list *p_id_list = p_list->p_id_lists[i]; -- int j, num_cpuids = 0, len_cpuids = 8; -+ uint32_t j, num_cpuids = 0, len_cpuids = 8; - ret = ABTU_malloc(sizeof(int) * len_cpuids, - (void **)&g_affinity.cpusets[i].cpuids); - ABTI_ASSERT(ret == ABT_SUCCESS); -@@ -313,7 +315,8 @@ void ABTD_affinity_init(const char *affinity_str) - g_affinity.initial_cpuset.num_cpuids); - int cpuid = g_affinity.initial_cpuset.cpuids[cpuid_i]; - /* If it is unique, add it.*/ -- int k, is_unique = 1; -+ uint32_t k; -+ int is_unique = 1; - for (k = 0; k < num_cpuids; k++) { - if (g_affinity.cpusets[i].cpuids[k] == cpuid) { - is_unique = 0; -@@ -373,7 +376,7 @@ void ABTD_affinity_finalize(void) - } - /* Free g_afinity. */ - ABTD_affinity_cpuset_destroy(&g_affinity.initial_cpuset); -- int i; -+ uint32_t i; - for (i = 0; i < g_affinity.num_cpusets; i++) { - ABTD_affinity_cpuset_destroy(&g_affinity.cpusets[i]); - } -diff --git a/src/arch/abtd_affinity_parser.c b/src/arch/abtd_affinity_parser.c -index 5329283..871ac45 100644 ---- a/src/arch/abtd_affinity_parser.c -+++ b/src/arch/abtd_affinity_parser.c -@@ -21,14 +21,14 @@ static void id_list_free(ABTD_affinity_id_list *p_id_list) - ABTU_free(p_id_list); - } - --static void id_list_add(ABTD_affinity_id_list *p_id_list, int id, int num, -+static void id_list_add(ABTD_affinity_id_list *p_id_list, int id, uint32_t num, - int stride) - { - /* Needs to add num ids. */ -- int i, ret; -- ret = ABTU_realloc(sizeof(int) * p_id_list->num, -- sizeof(int) * (p_id_list->num + num), -- (void **)&p_id_list->ids); -+ uint32_t i; -+ int ret = ABTU_realloc(sizeof(int) * p_id_list->num, -+ sizeof(int) * (p_id_list->num + num), -+ (void **)&p_id_list->ids); - ABTI_ASSERT(ret == ABT_SUCCESS); - for (i = 0; i < num; i++) { - p_id_list->ids[p_id_list->num + i] = id + stride * i; -@@ -48,7 +48,7 @@ static ABTD_affinity_list *list_create(void) - static void list_free(ABTD_affinity_list *p_list) - { - if (p_list) { -- int i; -+ uint32_t i; - for (i = 0; i < p_list->num; i++) - id_list_free(p_list->p_id_lists[i]); - free(p_list->p_id_lists); -@@ -57,10 +57,11 @@ static void list_free(ABTD_affinity_list *p_list) - } - - static void list_add(ABTD_affinity_list *p_list, ABTD_affinity_id_list *p_base, -- int num, int stride) -+ uint32_t num, int stride) - { - /* Needs to add num id-lists. */ -- int i, j, ret; -+ uint32_t i, j; -+ int ret; - - ret = ABTU_realloc(sizeof(ABTD_affinity_id_list *) * p_list->num, - sizeof(ABTD_affinity_id_list *) * (p_list->num + num), -@@ -86,9 +87,10 @@ static inline int is_whitespace(char c) - } - - /* Integer. */ --static int consume_int(const char *str, int *p_index, int *p_val) -+static int consume_int(const char *str, uint32_t *p_index, int *p_val) - { -- int index = *p_index, val = 0, val_sign = 1; -+ uint32_t index = *p_index; -+ int val = 0, val_sign = 1; - char flag = 'n'; - while (1) { - char c = *(str + index); -@@ -122,9 +124,10 @@ static int consume_int(const char *str, int *p_index, int *p_val) - } - - /* Positive integer */ --static int consume_pint(const char *str, int *p_index, int *p_val) -+static int consume_pint(const char *str, uint32_t *p_index, int *p_val) - { -- int index = *p_index, val; -+ uint32_t index = *p_index; -+ int val; - /* The value must be positive. */ - if (consume_int(str, &index, &val) && val > 0) { - *p_index = index; -@@ -135,9 +138,9 @@ static int consume_pint(const char *str, int *p_index, int *p_val) - } - - /* Symbol. If succeeded, it returns a consumed characters. */ --static int consume_symbol(const char *str, int *p_index, char symbol) -+static int consume_symbol(const char *str, uint32_t *p_index, char symbol) - { -- int index = *p_index; -+ uint32_t index = *p_index; - while (1) { - char c = *(str + index); - if (c == symbol) { -@@ -154,7 +157,7 @@ static int consume_symbol(const char *str, int *p_index, char symbol) - } - - static ABTD_affinity_id_list *parse_es_id_list(const char *affinity_str, -- int *p_index) -+ uint32_t *p_index) - { - ABTD_affinity_id_list *p_id_list = id_list_create(); - int val; -@@ -206,7 +209,7 @@ static ABTD_affinity_list *parse_list(const char *affinity_str) - { - if (!affinity_str) - return NULL; -- int index = 0; -+ uint32_t index = 0; - ABTD_affinity_list *p_list = list_create(); - ABTD_affinity_id_list *p_id_list = NULL; - while (1) { -diff --git a/src/arch/abtd_env.c b/src/arch/abtd_env.c -index f8c6dff..bd1188c 100644 ---- a/src/arch/abtd_env.c -+++ b/src/arch/abtd_env.c -@@ -13,7 +13,6 @@ - #define ABTD_SCHED_EVENT_FREQ 50 - #define ABTD_SCHED_SLEEP_NSEC 100 - --#define ABTD_OS_PAGE_SIZE (4 * 1024) - #define ABTD_HUGE_PAGE_SIZE (2 * 1024 * 1024) - #define ABTD_MEM_PAGE_SIZE (2 * 1024 * 1024) - #define ABTD_MEM_STACK_PAGE_SIZE (8 * 1024 * 1024) -@@ -21,243 +20,164 @@ - #define ABTD_MEM_MAX_TOTAL_STACK_SIZE (64 * 1024 * 1024) - #define ABTD_MEM_MAX_NUM_DESCS 4096 - -+/* To avoid potential overflow, we intentionally use a smaller value than the -+ * real limit. */ -+#define ABTD_ENV_INT_MAX ((int)(INT_MAX / 2)) -+#define ABTD_ENV_UINT32_MAX ((int)(UINT32_MAX / 2)) -+#define ABTD_ENV_UINT64_MAX ((int)(UINT64_MAX / 2)) -+#define ABTD_ENV_SIZE_MAX ((int)(SIZE_MAX / 2)) -+ -+static uint32_t roundup_pow2_uint32(uint32_t val); -+static const char *get_abt_env(const char *env_suffix); -+static ABT_bool is_false(const char *str, ABT_bool include0); -+static ABT_bool is_true(const char *str, ABT_bool include1); -+static ABT_bool load_env_bool(const char *env_suffix, ABT_bool default_val); -+static int load_env_int(const char *env_suffix, int default_val, int min_val, -+ int max_val); -+static uint32_t load_env_uint32(const char *env_suffix, uint32_t default_val, -+ uint32_t min_val, uint32_t max_val); -+static uint64_t load_env_uint64(const char *env_suffix, uint64_t default_val, -+ uint64_t min_val, uint64_t max_val); -+static size_t load_env_size(const char *env_suffix, size_t default_val, -+ size_t min_val, size_t max_val); -+ - void ABTD_env_init(ABTI_global *p_global) - { -- char *env; -+ const char *env; - - /* Get the number of available cores in the system */ - p_global->num_cores = sysconf(_SC_NPROCESSORS_ONLN); - -- /* By default, we use the CPU affinity */ -- p_global->set_affinity = ABT_TRUE; -- env = getenv("ABT_SET_AFFINITY"); -- if (env == NULL) -- env = getenv("ABT_ENV_SET_AFFINITY"); -- if (env != NULL) { -- if (strcasecmp(env, "n") == 0 || strcasecmp(env, "no") == 0) { -- p_global->set_affinity = ABT_FALSE; -- } -- } -- if (p_global->set_affinity == ABT_TRUE) { -+ /* ABT_SET_AFFINITY, ABT_ENV_SET_AFFINITY */ -+ env = get_abt_env("SET_AFFINITY"); -+ if (env != NULL && is_false(env, ABT_FALSE)) { -+ p_global->set_affinity = ABT_FALSE; -+ } else { -+ /* By default, we use the CPU affinity */ -+ p_global->set_affinity = ABT_TRUE; - ABTD_affinity_init(env); - } - - #ifdef ABT_CONFIG_USE_DEBUG_LOG_PRINT - /* If the debug log printing is set in configure, logging is turned on by - * default. */ -- p_global->use_logging = ABT_TRUE; -- p_global->use_debug = ABT_TRUE; -+ const ABT_bool default_use_logging = ABT_TRUE; -+ const ABT_bool default_use_debug = ABT_TRUE; - #else - /* Otherwise, logging is not turned on by default. */ -- p_global->use_logging = ABT_FALSE; -- p_global->use_debug = ABT_FALSE; -+ const ABT_bool default_use_logging = ABT_FALSE; -+ const ABT_bool default_use_debug = ABT_FALSE; - #endif -- env = getenv("ABT_USE_LOG"); -- if (env == NULL) -- env = getenv("ABT_ENV_USE_LOG"); -- if (env != NULL) { -- if (strcmp(env, "0") == 0 || strcasecmp(env, "n") == 0 || -- strcasecmp(env, "no") == 0) { -- p_global->use_logging = ABT_FALSE; -- } else { -- p_global->use_logging = ABT_TRUE; -- } -- } -- env = getenv("ABT_USE_DEBUG"); -- if (env == NULL) -- env = getenv("ABT_ENV_USE_DEBUG"); -- if (env != NULL) { -- if (strcmp(env, "0") == 0 || strcasecmp(env, "n") == 0 || -- strcasecmp(env, "no") == 0) { -- p_global->use_debug = ABT_FALSE; -- } else { -- p_global->use_debug = ABT_TRUE; -- } -- } -+ /* ABT_USE_LOG, ABT_ENV_USE_LOG */ -+ p_global->use_logging = load_env_bool("USE_LOG", default_use_logging); - -- /* Maximum size of the internal ES array */ -- env = getenv("ABT_MAX_NUM_XSTREAMS"); -- if (env == NULL) -- env = getenv("ABT_ENV_MAX_NUM_XSTREAMS"); -- if (env != NULL) { -- p_global->max_xstreams = atoi(env); -- } else { -- p_global->max_xstreams = p_global->num_cores; -- } -+ /* ABT_USE_DEBUG, ABT_ENV_USE_DEBUG */ -+ p_global->use_debug = load_env_bool("USE_DEBUG", default_use_debug); - -- /* Default key table size */ -- env = getenv("ABT_KEY_TABLE_SIZE"); -- if (env == NULL) -- env = getenv("ABT_ENV_KEY_TABLE_SIZE"); -- if (env != NULL) { -- p_global->key_table_size = (int)atoi(env); -- } else { -- p_global->key_table_size = ABTD_KEY_TABLE_DEFAULT_SIZE; -- } -- /* key_table_size must be a power of 2. */ -- { -- int i; -- for (i = 0; i < sizeof(int) * 8; i++) { -- if ((p_global->key_table_size - 1) >> i == 0) -- break; -- } -- p_global->key_table_size = 1 << i; -- } -+ /* ABT_MAX_NUM_XSTREAMS, ABT_ENV_MAX_NUM_XSTREAMS -+ * Maximum size of the internal ES array */ -+ p_global->max_xstreams = -+ load_env_int("MAX_NUM_XSTREAMS", p_global->num_cores, 1, -+ ABTD_ENV_INT_MAX); - -- /* Default stack size for ULT */ -- env = getenv("ABT_THREAD_STACKSIZE"); -- if (env == NULL) -- env = getenv("ABT_ENV_THREAD_STACKSIZE"); -- if (env != NULL) { -- p_global->thread_stacksize = (size_t)atol(env); -- ABTI_ASSERT(p_global->thread_stacksize >= 512); -- } else { -- p_global->thread_stacksize = ABTD_THREAD_DEFAULT_STACKSIZE; -- } -- /* Stack size must be a multiple of cacheline size. */ -- p_global->thread_stacksize = -- (p_global->thread_stacksize + ABT_CONFIG_STATIC_CACHELINE_SIZE - 1) & -- (~(ABT_CONFIG_STATIC_CACHELINE_SIZE - 1)); -+ /* ABT_KEY_TABLE_SIZE, ABT_ENV_KEY_TABLE_SIZE -+ * Default key table size */ -+ p_global->key_table_size = roundup_pow2_uint32( -+ load_env_uint32("KEY_TABLE_SIZE", ABTD_KEY_TABLE_DEFAULT_SIZE, 1, -+ ABTD_ENV_UINT32_MAX)); - -- /* Default stack size for scheduler */ -- env = getenv("ABT_SCHED_STACKSIZE"); -- if (env == NULL) -- env = getenv("ABT_ENV_SCHED_STACKSIZE"); -- if (env != NULL) { -- p_global->sched_stacksize = (size_t)atol(env); -- ABTI_ASSERT(p_global->sched_stacksize >= 512); -- } else { -- p_global->sched_stacksize = ABTD_SCHED_DEFAULT_STACKSIZE; -- } -+ /* ABT_THREAD_STACKSIZE, ABT_ENV_THREAD_STACKSIZE -+ * Default stack size for ULT */ -+ p_global->thread_stacksize = -+ ABTU_roundup_size(load_env_size("THREAD_STACKSIZE", -+ ABTD_THREAD_DEFAULT_STACKSIZE, 512, -+ ABTD_ENV_SIZE_MAX), -+ ABT_CONFIG_STATIC_CACHELINE_SIZE); - -- /* Default frequency for event checking by the scheduler */ -- env = getenv("ABT_SCHED_EVENT_FREQ"); -- if (env == NULL) -- env = getenv("ABT_ENV_SCHED_EVENT_FREQ"); -- if (env != NULL) { -- p_global->sched_event_freq = (uint32_t)atol(env); -- ABTI_ASSERT(p_global->sched_event_freq >= 1); -- } else { -- p_global->sched_event_freq = ABTD_SCHED_EVENT_FREQ; -- } -+ /* ABT_SCHED_STACKSIZE, ABT_ENV_SCHED_STACKSIZE -+ * Default stack size for scheduler */ -+ p_global->sched_stacksize = -+ ABTU_roundup_size(load_env_size("SCHED_STACKSIZE", -+ ABTD_SCHED_DEFAULT_STACKSIZE, 512, -+ ABTD_ENV_SIZE_MAX), -+ ABT_CONFIG_STATIC_CACHELINE_SIZE); - -- /* Default nanoseconds for scheduler sleep */ -- env = getenv("ABT_SCHED_SLEEP_NSEC"); -- if (env == NULL) -- env = getenv("ABT_ENV_SCHED_SLEEP_NSEC"); -- if (env != NULL) { -- p_global->sched_sleep_nsec = atol(env); -- ABTI_ASSERT(p_global->sched_sleep_nsec >= 0); -- } else { -- p_global->sched_sleep_nsec = ABTD_SCHED_SLEEP_NSEC; -- } -+ /* ABT_SCHED_EVENT_FREQ, ABT_ENV_SCHED_EVENT_FREQ -+ * Default frequency for event checking by the scheduler */ -+ p_global->sched_event_freq = -+ load_env_uint32("SCHED_EVENT_FREQ", ABTD_SCHED_EVENT_FREQ, 1, -+ ABTD_ENV_UINT32_MAX); - -- /* Mutex attributes */ -- env = getenv("ABT_MUTEX_MAX_HANDOVERS"); -- if (env == NULL) -- env = getenv("ABT_ENV_MUTEX_MAX_HANDOVERS"); -- if (env != NULL) { -- p_global->mutex_max_handovers = (uint32_t)atoi(env); -- ABTI_ASSERT(p_global->mutex_max_handovers >= 1); -- } else { -- p_global->mutex_max_handovers = 64; -- } -+ /* ABT_SCHED_SLEEP_NSEC, ABT_ENV_SCHED_SLEEP_NSEC -+ * Default nanoseconds for scheduler sleep */ -+ p_global->sched_sleep_nsec = -+ load_env_uint64("SCHED_SLEEP_NSEC", ABTD_SCHED_SLEEP_NSEC, 0, -+ ABTD_ENV_UINT64_MAX); - -- env = getenv("ABT_MUTEX_MAX_WAKEUPS"); -- if (env == NULL) -- env = getenv("ABT_ENV_MUTEX_MAX_WAKEUPS"); -- if (env != NULL) { -- p_global->mutex_max_wakeups = (uint32_t)atoi(env); -- ABTI_ASSERT(p_global->mutex_max_wakeups >= 1); -- } else { -- p_global->mutex_max_wakeups = 1; -- } -+ /* ABT_MUTEX_MAX_HANDOVERS, ABT_ENV_MUTEX_MAX_HANDOVERS -+ * Default maximum number of mutex handover */ -+ p_global->mutex_max_handovers = -+ load_env_uint32("MUTEX_MAX_HANDOVERS", 64, 1, ABTD_ENV_UINT32_MAX); - -- /* OS page size */ -- env = getenv("ABT_OS_PAGE_SIZE"); -- if (env == NULL) -- env = getenv("ABT_ENV_OS_PAGE_SIZE"); -- if (env != NULL) { -- p_global->os_page_size = (uint32_t)atol(env); -- } else { -- p_global->os_page_size = ABTD_OS_PAGE_SIZE; -- } -+ /* ABT_MUTEX_MAX_WAKEUPS, ABT_ENV_MUTEX_MAX_WAKEUPS -+ * Default maximum number of mutex wakeup operations */ -+ p_global->mutex_max_wakeups = -+ load_env_uint32("MUTEX_MAX_WAKEUPS", 1, 1, ABTD_ENV_UINT32_MAX); - -- /* Huge page size */ -- env = getenv("ABT_HUGE_PAGE_SIZE"); -- if (env == NULL) -- env = getenv("ABT_ENV_HUGE_PAGE_SIZE"); -- if (env != NULL) { -- p_global->huge_page_size = (uint32_t)atol(env); -- } else { -- p_global->huge_page_size = ABTD_HUGE_PAGE_SIZE; -- } -+ /* ABT_HUGE_PAGE_SIZE, ABT_ENV_HUGE_PAGE_SIZE -+ * Huge page size */ -+ p_global->huge_page_size = -+ load_env_size("HUGE_PAGE_SIZE", ABTD_HUGE_PAGE_SIZE, 4096, -+ ABTD_ENV_SIZE_MAX); - - #ifdef ABT_CONFIG_USE_MEM_POOL -- /* Page size for memory allocation */ -- env = getenv("ABT_MEM_PAGE_SIZE"); -- if (env == NULL) -- env = getenv("ABT_ENV_MEM_PAGE_SIZE"); -- if (env != NULL) { -- p_global->mem_page_size = (uint32_t)atol(env); -- } else { -- p_global->mem_page_size = ABTD_MEM_PAGE_SIZE; -- } -+ /* ABT_MEM_PAGE_SIZE, ABT_ENV_MEM_PAGE_SIZE -+ * Page size for memory allocation */ -+ p_global->mem_page_size = -+ ABTU_roundup_size(load_env_size("MEM_PAGE_SIZE", ABTD_MEM_PAGE_SIZE, -+ 4096, ABTD_ENV_SIZE_MAX), -+ ABT_CONFIG_STATIC_CACHELINE_SIZE); - -- /* Stack page size for memory allocation */ -- env = getenv("ABT_MEM_STACK_PAGE_SIZE"); -- if (env == NULL) -- env = getenv("ABT_ENV_MEM_STACK_PAGE_SIZE"); -- if (env != NULL) { -- p_global->mem_sp_size = (size_t)atol(env); -- } else { -- p_global->mem_sp_size = ABTD_MEM_STACK_PAGE_SIZE; -- } -+ /* ABT_MEM_STACK_PAGE_SIZE, ABT_ENV_MEM_STACK_PAGE_SIZE -+ * Stack page size for memory allocation */ -+ p_global->mem_sp_size = -+ ABTU_roundup_size(load_env_size("MEM_STACK_PAGE_SIZE", -+ ABTD_MEM_STACK_PAGE_SIZE, -+ p_global->thread_stacksize * 4, -+ ABTD_ENV_SIZE_MAX), -+ ABT_CONFIG_STATIC_CACHELINE_SIZE); - -- /* Maximum number of stacks that each ES can keep during execution */ -- env = getenv("ABT_MEM_MAX_NUM_STACKS"); -- if (env == NULL) -- env = getenv("ABT_ENV_MEM_MAX_NUM_STACKS"); -- if (env != NULL) { -- p_global->mem_max_stacks = (uint32_t)atol(env); -- } else { -- if (p_global->thread_stacksize * ABTD_MEM_MAX_NUM_STACKS > -- ABTD_MEM_MAX_TOTAL_STACK_SIZE) { -- /* Each execution stream caches too many stacks in total. Let's -- * reduce the max # of stacks. */ -- p_global->mem_max_stacks = -- ABTD_MEM_MAX_TOTAL_STACK_SIZE / p_global->thread_stacksize; -- } else { -- p_global->mem_max_stacks = ABTD_MEM_MAX_NUM_STACKS; -- } -- } -+ /* ABT_MEM_MAX_NUM_STACKS, ABT_ENV_MEM_MAX_NUM_STACKS -+ * Maximum number of stacks that each ES can keep during execution. */ -+ /* If each execution stream caches too many stacks in total, let's reduce -+ * the max # of stacks. */ -+ const uint32_t default_mem_max_stacks = -+ ABTU_min_uint32(ABTD_MEM_MAX_TOTAL_STACK_SIZE / -+ p_global->thread_stacksize, -+ ABTD_MEM_MAX_NUM_STACKS); - /* The value must be a multiple of ABT_MEM_POOL_MAX_LOCAL_BUCKETS. */ - p_global->mem_max_stacks = -- ((p_global->mem_max_stacks + ABT_MEM_POOL_MAX_LOCAL_BUCKETS - 1) / -- ABT_MEM_POOL_MAX_LOCAL_BUCKETS) * -- ABT_MEM_POOL_MAX_LOCAL_BUCKETS; -- -- /* Maximum number of descriptors that each ES can keep during execution */ -- env = getenv("ABT_MEM_MAX_NUM_DESCS"); -- if (env == NULL) -- env = getenv("ABT_ENV_MEM_MAX_NUM_DESCS"); -- if (env != NULL) { -- p_global->mem_max_descs = (uint32_t)atol(env); -- } else { -- p_global->mem_max_descs = ABTD_MEM_MAX_NUM_DESCS; -- } -+ ABTU_roundup_uint32(load_env_uint32("MEM_MAX_NUM_STACKS", -+ default_mem_max_stacks, -+ ABT_MEM_POOL_MAX_LOCAL_BUCKETS, -+ ABTD_ENV_UINT32_MAX), -+ ABT_MEM_POOL_MAX_LOCAL_BUCKETS); -+ -+ /* ABT_MEM_MAX_NUM_DESCS, ABT_ENV_MEM_MAX_NUM_DESCS -+ * Maximum number of descriptors that each ES can keep during execution */ - /* The value must be a multiple of ABT_MEM_POOL_MAX_LOCAL_BUCKETS. */ - p_global->mem_max_descs = -- ((p_global->mem_max_descs + ABT_MEM_POOL_MAX_LOCAL_BUCKETS - 1) / -- ABT_MEM_POOL_MAX_LOCAL_BUCKETS) * -- ABT_MEM_POOL_MAX_LOCAL_BUCKETS; -+ ABTU_roundup_uint32(load_env_uint32("MEM_MAX_NUM_DESCS", -+ ABTD_MEM_MAX_NUM_DESCS, -+ ABT_MEM_POOL_MAX_LOCAL_BUCKETS, -+ ABTD_ENV_UINT32_MAX), -+ ABT_MEM_POOL_MAX_LOCAL_BUCKETS); - -- /* How to allocate large pages. The default is to use mmap() for huge -+ /* ABT_MEM_LP_ALLOC, ABT_ENV_MEM_LP_ALLOC -+ * How to allocate large pages. The default is to use mmap() for huge - * pages and then to fall back to allocate regular pages using mmap() when - * huge pages are run out of. */ -- env = getenv("ABT_MEM_LP_ALLOC"); -- if (env == NULL) -- env = getenv("ABT_ENV_MEM_LP_ALLOC"); -+ env = get_abt_env("MEM_LP_ALLOC"); - #if defined(HAVE_MAP_ANONYMOUS) || defined(HAVE_MAP_ANON) - #if defined(__x86_64__) - int lp_alloc = ABTI_MEM_LP_MMAP_HP_RP; -@@ -302,21 +222,153 @@ void ABTD_env_init(ABTI_global *p_global) - } - #endif - -- /* Whether to print the configuration on ABT_init() */ -- env = getenv("ABT_PRINT_CONFIG"); -- if (env == NULL) -- env = getenv("ABT_ENV_PRINT_CONFIG"); -- if (env != NULL) { -- if (strcmp(env, "1") == 0 || strcasecmp(env, "yes") == 0 || -- strcasecmp(env, "y") == 0) { -- p_global->print_config = ABT_TRUE; -+ /* ABT_PRINT_CONFIG, ABT_ENV_PRINT_CONFIG -+ * Whether to print the configuration on ABT_init() */ -+ p_global->print_config = load_env_bool("PRINT_CONFIG", ABT_FALSE); -+ -+ /* Init timer */ -+ ABTD_time_init(); -+} -+ -+/*****************************************************************************/ -+/* Internal static functions */ -+/*****************************************************************************/ -+ -+static uint32_t roundup_pow2_uint32(uint32_t val) -+{ -+ /* 3 -> 4 -+ * 4 -> 4 -+ * 5 -> 8 */ -+ if (val == 0) -+ return 0; -+ uint32_t i; -+ for (i = 0; i < sizeof(uint32_t) * 8; i++) { -+ if ((val - 1) >> i == 0) -+ break; -+ } -+ return ((uint32_t)1) << i; -+} -+ -+static const char *get_abt_env(const char *env_suffix) -+{ -+ /* Valid prefix is ABT_ and ABT_ENV_. ABT_ is prioritized. */ -+ char buffer[128]; -+ const char *prefixes[] = { "ABT_", "ABT_ENV_" }; -+ uint32_t i; -+ for (i = 0; i < sizeof(prefixes) / sizeof(prefixes[0]); i++) { -+ strcpy(buffer, prefixes[i]); -+ strcpy(buffer + strlen(prefixes[i]), env_suffix); -+ const char *env = getenv(buffer); -+ if (env) -+ return env; -+ } -+ return NULL; -+} -+ -+static ABT_bool is_false(const char *str, ABT_bool include0) -+{ -+ if (include0 && strcmp(str, "0") == 0) { -+ return ABT_TRUE; -+ } else if (strcasecmp(str, "n") == 0 || strcasecmp(str, "no") == 0 || -+ strcasecmp(str, "false") == 0 || strcasecmp(str, "off") == 0) { -+ return ABT_TRUE; -+ } -+ return ABT_FALSE; -+} -+ -+static ABT_bool is_true(const char *str, ABT_bool include1) -+{ -+ if (include1 && strcmp(str, "1") == 0) { -+ return ABT_TRUE; -+ } else if (strcasecmp(str, "y") == 0 || strcasecmp(str, "yes") == 0 || -+ strcasecmp(str, "true") == 0 || strcasecmp(str, "on") == 0) { -+ return ABT_TRUE; -+ } -+ return ABT_FALSE; -+} -+ -+static ABT_bool load_env_bool(const char *env_suffix, ABT_bool default_val) -+{ -+ const char *env = get_abt_env(env_suffix); -+ if (!env) { -+ return default_val; -+ } else { -+ if (default_val) { -+ /* If env is not "false", return true */ -+ return is_false(env, ABT_TRUE) ? ABT_FALSE : ABT_TRUE; - } else { -- p_global->print_config = ABT_FALSE; -+ /* If env is not "true", return false */ -+ return is_true(env, ABT_TRUE) ? ABT_TRUE : ABT_FALSE; - } -+ } -+} -+ -+static int load_env_int(const char *env_suffix, int default_val, int min_val, -+ int max_val) -+{ -+ const char *env = get_abt_env(env_suffix); -+ if (!env) { -+ return ABTU_max_int(min_val, ABTU_min_int(max_val, default_val)); - } else { -- p_global->print_config = ABT_FALSE; -+ int val; -+ int abt_errno = ABTU_atoi(env, &val, NULL); -+ if (abt_errno != ABT_SUCCESS) { -+ return ABTU_max_int(min_val, ABTU_min_int(max_val, default_val)); -+ } else { -+ return ABTU_max_int(min_val, ABTU_min_int(max_val, val)); -+ } - } -+} - -- /* Init timer */ -- ABTD_time_init(); -+static uint32_t load_env_uint32(const char *env_suffix, uint32_t default_val, -+ uint32_t min_val, uint32_t max_val) -+{ -+ const char *env = get_abt_env(env_suffix); -+ if (!env) { -+ return ABTU_max_uint32(min_val, ABTU_min_uint32(max_val, default_val)); -+ } else { -+ uint32_t val; -+ int abt_errno = ABTU_atoui32(env, &val, NULL); -+ if (abt_errno != ABT_SUCCESS) { -+ return ABTU_max_uint32(min_val, -+ ABTU_min_uint32(max_val, default_val)); -+ } else { -+ return ABTU_max_uint32(min_val, ABTU_min_uint32(max_val, val)); -+ } -+ } -+} -+ -+static uint64_t load_env_uint64(const char *env_suffix, uint64_t default_val, -+ uint64_t min_val, uint64_t max_val) -+{ -+ const char *env = get_abt_env(env_suffix); -+ if (!env) { -+ return ABTU_max_uint64(min_val, ABTU_min_uint64(max_val, default_val)); -+ } else { -+ uint64_t val; -+ int abt_errno = ABTU_atoui64(env, &val, NULL); -+ if (abt_errno != ABT_SUCCESS) { -+ return ABTU_max_uint64(min_val, -+ ABTU_min_uint64(max_val, default_val)); -+ } else { -+ return ABTU_max_uint64(min_val, ABTU_min_uint64(max_val, val)); -+ } -+ } -+} -+ -+static size_t load_env_size(const char *env_suffix, size_t default_val, -+ size_t min_val, size_t max_val) -+{ -+ const char *env = get_abt_env(env_suffix); -+ if (!env) { -+ return ABTU_max_size(min_val, ABTU_min_size(max_val, default_val)); -+ } else { -+ size_t val; -+ int abt_errno = ABTU_atosz(env, &val, NULL); -+ if (abt_errno != ABT_SUCCESS) { -+ return ABTU_max_size(min_val, ABTU_min_size(max_val, default_val)); -+ } else { -+ return ABTU_max_size(min_val, ABTU_min_size(max_val, val)); -+ } -+ } - } -diff --git a/src/arch/abtd_stream.c b/src/arch/abtd_stream.c -index d9ba075..0818028 100644 ---- a/src/arch/abtd_stream.c -+++ b/src/arch/abtd_stream.c -@@ -108,3 +108,29 @@ void ABTD_xstream_context_set_self(ABTD_xstream_context *p_ctx) - { - p_ctx->native_thread = pthread_self(); - } -+ -+void ABTD_xstream_context_print(ABTD_xstream_context *p_ctx, FILE *p_os, -+ int indent) -+{ -+ if (p_ctx == NULL) { -+ fprintf(p_os, "%*s== NULL XSTREAM CONTEXT ==\n", indent, ""); -+ } else { -+ const char *state; -+ if (p_ctx->state == ABTD_XSTREAM_CONTEXT_STATE_RUNNING) { -+ state = "RUNNING"; -+ } else if (p_ctx->state == ABTD_XSTREAM_CONTEXT_STATE_WAITING) { -+ state = "WAITING"; -+ } else if (p_ctx->state == ABTD_XSTREAM_CONTEXT_STATE_REQ_JOIN) { -+ state = "REQ_JOIN"; -+ } else if (p_ctx->state == ABTD_XSTREAM_CONTEXT_STATE_REQ_TERMINATE) { -+ state = "REQ_TERMINATE"; -+ } else { -+ state = "UNKNOWN"; -+ } -+ fprintf(p_os, -+ "%*s== XSTREAM CONTEXT (%p) ==\n" -+ "%*sstate : %s\n", -+ indent, "", (void *)p_ctx, indent, "", state); -+ } -+ fflush(p_os); -+} -diff --git a/src/arch/fcontext/jump_x86_64_sysv_elf_gas.S b/src/arch/fcontext/jump_x86_64_sysv_elf_gas.S -index 3c8a2ac..e12b702 100644 ---- a/src/arch/fcontext/jump_x86_64_sysv_elf_gas.S -+++ b/src/arch/fcontext/jump_x86_64_sysv_elf_gas.S -@@ -133,6 +133,26 @@ init_and_call_fcontext: - .size init_and_call_fcontext,.-init_and_call_fcontext - #endif - -+.text -+.globl peek_fcontext -+.type peek_fcontext,@function -+.align 16 -+peek_fcontext: -+ /* temporarily move RSP (pointing to context-data) to R12 (callee-saved) */ -+ pushq %r12 -+ movq %rsp, %r12 -+ /* restore RSP (pointing to context-data) from RDI */ -+ movq %rdi, %rsp -+ /* RSP is already 16-byte aligned, so we can call a peek funciton here -+ * rsi(rdx) => second_arg(third_arg) */ -+ movq %rdx, %rdi -+ callq *%rsi -+ /* restore callee-saved registers. */ -+ movq %r12, %rsp -+ popq %r12 -+ ret -+.size peek_fcontext,.-peek_fcontext -+ - /* Mark that we don't need executable stack. */ - #ifndef __SUNPRO_C - .section .note.GNU-stack,"",%progbits -diff --git a/src/barrier.c b/src/barrier.c -index 99686f6..88bffb7 100644 ---- a/src/barrier.c -+++ b/src/barrier.c -@@ -27,27 +27,15 @@ int ABT_barrier_create(uint32_t num_waiters, ABT_barrier *newbarrier) - { - int abt_errno; - ABTI_barrier *p_newbarrier; -+ size_t arg_num_waiters = num_waiters; - - abt_errno = ABTU_malloc(sizeof(ABTI_barrier), (void **)&p_newbarrier); - ABTI_CHECK_ERROR(abt_errno); - - ABTI_spinlock_clear(&p_newbarrier->lock); -- p_newbarrier->num_waiters = num_waiters; -+ p_newbarrier->num_waiters = arg_num_waiters; - p_newbarrier->counter = 0; -- abt_errno = ABTU_malloc(num_waiters * sizeof(ABTI_ythread *), -- (void **)&p_newbarrier->waiters); -- if (ABTI_IS_ERROR_CHECK_ENABLED && abt_errno != ABT_SUCCESS) { -- ABTU_free(p_newbarrier); -- ABTI_HANDLE_ERROR(abt_errno); -- } -- abt_errno = ABTU_malloc(num_waiters * sizeof(ABT_unit_type), -- (void **)&p_newbarrier->waiter_type); -- if (ABTI_IS_ERROR_CHECK_ENABLED && abt_errno != ABT_SUCCESS) { -- ABTU_free(p_newbarrier->waiters); -- ABTU_free(p_newbarrier); -- ABTI_HANDLE_ERROR(abt_errno); -- } -- -+ ABTI_waitlist_init(&p_newbarrier->waitlist); - /* Return value */ - *newbarrier = ABTI_barrier_get_handle(p_newbarrier); - return ABT_SUCCESS; -@@ -71,31 +59,13 @@ int ABT_barrier_reinit(ABT_barrier barrier, uint32_t num_waiters) - ABTI_barrier *p_barrier = ABTI_barrier_get_ptr(barrier); - ABTI_CHECK_NULL_BARRIER_PTR(p_barrier); - ABTI_ASSERT(p_barrier->counter == 0); -+ size_t arg_num_waiters = num_waiters; - - /* Only when num_waiters is different from p_barrier->num_waiters, we - * change p_barrier. */ -- if (num_waiters < p_barrier->num_waiters) { -+ if (arg_num_waiters != p_barrier->num_waiters) { - /* We can reuse waiters and waiter_type arrays */ -- p_barrier->num_waiters = num_waiters; -- } else if (num_waiters > p_barrier->num_waiters) { -- /* Free existing arrays and reallocate them */ -- int abt_errno; -- ABTI_ythread **new_waiters; -- ABT_unit_type *new_waiter_types; -- abt_errno = ABTU_malloc(num_waiters * sizeof(ABTI_ythread *), -- (void **)&new_waiters); -- ABTI_CHECK_ERROR(abt_errno); -- abt_errno = ABTU_malloc(num_waiters * sizeof(ABT_unit_type), -- (void **)&new_waiter_types); -- if (ABTI_IS_ERROR_CHECK_ENABLED && abt_errno != ABT_SUCCESS) { -- ABTU_free(new_waiters); -- ABTI_HANDLE_ERROR(abt_errno); -- } -- p_barrier->num_waiters = num_waiters; -- ABTU_free(p_barrier->waiters); -- ABTU_free(p_barrier->waiter_type); -- p_barrier->waiters = new_waiters; -- p_barrier->waiter_type = new_waiter_types; -+ p_barrier->num_waiters = arg_num_waiters; - } - return ABT_SUCCESS; - } -@@ -118,15 +88,14 @@ int ABT_barrier_free(ABT_barrier *barrier) - ABTI_barrier *p_barrier = ABTI_barrier_get_ptr(h_barrier); - ABTI_CHECK_NULL_BARRIER_PTR(p_barrier); - -- ABTI_ASSERT(p_barrier->counter == 0); -- - /* The lock needs to be acquired to safely free the barrier structure. - * However, we do not have to unlock it because the entire structure is - * freed here. */ - ABTI_spinlock_acquire(&p_barrier->lock); - -- ABTU_free(p_barrier->waiters); -- ABTU_free(p_barrier->waiter_type); -+ /* p_barrier->counter must be checked after taking a lock. */ -+ ABTI_ASSERT(p_barrier->counter == 0); -+ - ABTU_free(p_barrier); - - /* Return value */ -@@ -150,77 +119,22 @@ int ABT_barrier_wait(ABT_barrier barrier) - ABTI_local *p_local = ABTI_local_get_local(); - ABTI_barrier *p_barrier = ABTI_barrier_get_ptr(barrier); - ABTI_CHECK_NULL_BARRIER_PTR(p_barrier); -- uint32_t pos; - - ABTI_spinlock_acquire(&p_barrier->lock); - - ABTI_ASSERT(p_barrier->counter < p_barrier->num_waiters); -- pos = p_barrier->counter++; -+ p_barrier->counter++; - - /* If we do not have all the waiters yet */ - if (p_barrier->counter < p_barrier->num_waiters) { -- ABTI_ythread *p_ythread = NULL; -- ABT_unit_type type; -- ABTD_atomic_int32 ext_signal = ABTD_ATOMIC_INT32_STATIC_INITIALIZER(0); -- -- ABTI_xstream *p_local_xstream = ABTI_local_get_xstream_or_null(p_local); -- if (!ABTI_IS_EXT_THREAD_ENABLED || p_local_xstream) { -- p_ythread = -- ABTI_thread_get_ythread_or_null(p_local_xstream->p_thread); -- } -- if (p_ythread) { -- /* yieldable thread */ -- type = ABT_UNIT_TYPE_THREAD; -- } else { -- /* external thread or non-yieldable thread */ -- /* Check size if ext_signal can be stored in p_thread. */ -- ABTI_STATIC_ASSERT(sizeof(ext_signal) <= sizeof(p_ythread)); -- p_ythread = (ABTI_ythread *)&ext_signal; -- type = ABT_UNIT_TYPE_EXT; -- } -- -- /* Keep the waiter's information */ -- p_barrier->waiters[pos] = p_ythread; -- p_barrier->waiter_type[pos] = type; -- -- if (type == ABT_UNIT_TYPE_THREAD) { -- /* Change the ULT's state to BLOCKED */ -- ABTI_ythread_set_blocked(p_ythread); -- } -- -- ABTI_spinlock_release(&p_barrier->lock); -- -- if (type == ABT_UNIT_TYPE_THREAD) { -- /* Suspend the current ULT */ -- ABTI_ythread_suspend(&p_local_xstream, p_ythread, -- ABT_SYNC_EVENT_TYPE_BARRIER, -- (void *)p_barrier); -- } else { -- /* External thread is waiting here polling ext_signal. */ -- /* FIXME: need a better implementation */ -- while (!ABTD_atomic_acquire_load_int32(&ext_signal)) -- ; -- } -+ ABTI_waitlist_wait_and_unlock(&p_local, &p_barrier->waitlist, -+ &p_barrier->lock, ABT_FALSE, -+ ABT_SYNC_EVENT_TYPE_BARRIER, -+ (void *)p_barrier); - } else { -- /* Signal all the waiting ULTs */ -- int i; -- for (i = 0; i < p_barrier->num_waiters - 1; i++) { -- ABTI_ythread *p_ythread = p_barrier->waiters[i]; -- if (p_barrier->waiter_type[i] == ABT_UNIT_TYPE_THREAD) { -- ABTI_ythread_set_ready(p_local, p_ythread); -- } else { -- /* When p_cur is an external thread */ -- ABTD_atomic_int32 *p_ext_signal = -- (ABTD_atomic_int32 *)p_ythread; -- ABTD_atomic_release_store_int32(p_ext_signal, 1); -- } -- -- p_barrier->waiters[i] = NULL; -- } -- -+ ABTI_waitlist_broadcast(p_local, &p_barrier->waitlist); - /* Reset counter */ - p_barrier->counter = 0; -- - ABTI_spinlock_release(&p_barrier->lock); - } - return ABT_SUCCESS; -diff --git a/src/cond.c b/src/cond.c -index 8a0af51..30ad62f 100644 ---- a/src/cond.c -+++ b/src/cond.c -@@ -6,6 +6,8 @@ - #include "abti.h" - #include - -+static inline double convert_timespec_to_sec(const struct timespec *p_ts); -+ - /** @defgroup COND Condition Variable - * This group is for Condition Variable. - */ -@@ -52,7 +54,7 @@ int ABT_cond_free(ABT_cond *cond) - ABT_cond h_cond = *cond; - ABTI_cond *p_cond = ABTI_cond_get_ptr(h_cond); - ABTI_CHECK_NULL_COND_PTR(p_cond); -- ABTI_CHECK_TRUE(p_cond->num_waiters == 0, ABT_ERR_COND); -+ ABTI_CHECK_TRUE(!ABTI_waitlist_is_empty(&p_cond->waitlist), ABT_ERR_COND); - - ABTI_cond_fini(p_cond); - ABTU_free(p_cond); -@@ -91,47 +93,6 @@ int ABT_cond_wait(ABT_cond cond, ABT_mutex mutex) - return ABT_SUCCESS; - } - --static inline double convert_timespec_to_sec(const struct timespec *p_ts) --{ -- double secs; -- secs = ((double)p_ts->tv_sec) + 1.0e-9 * ((double)p_ts->tv_nsec); -- return secs; --} -- --static inline void remove_thread(ABTI_cond *p_cond, ABTI_thread *p_thread) --{ -- if (p_thread->p_next == NULL) -- return; -- -- ABTI_spinlock_acquire(&p_cond->lock); -- -- if (p_thread->p_next == NULL) { -- ABTI_spinlock_release(&p_cond->lock); -- return; -- } -- -- /* If p_thread is still in the queue, we have to remove it. */ -- p_cond->num_waiters--; -- if (p_cond->num_waiters == 0) { -- p_cond->p_waiter_mutex = NULL; -- p_cond->p_head = NULL; -- p_cond->p_tail = NULL; -- } else { -- p_thread->p_prev->p_next = p_thread->p_next; -- p_thread->p_next->p_prev = p_thread->p_prev; -- if (p_thread == p_cond->p_head) { -- p_cond->p_head = p_thread->p_next; -- } else if (p_thread == p_cond->p_tail) { -- p_cond->p_tail = p_thread->p_prev; -- } -- } -- -- ABTI_spinlock_release(&p_cond->lock); -- -- p_thread->p_prev = NULL; -- p_thread->p_next = NULL; --} -- - /** - * @ingroup COND - * @brief Wait on the condition. -@@ -180,51 +141,17 @@ int ABT_cond_timedwait(ABT_cond cond, ABT_mutex mutex, - } - } - -- if (p_cond->num_waiters == 0) { -- thread.p_prev = &thread; -- thread.p_next = &thread; -- p_cond->p_head = &thread; -- p_cond->p_tail = &thread; -- } else { -- p_cond->p_tail->p_next = &thread; -- p_cond->p_head->p_prev = &thread; -- thread.p_prev = p_cond->p_tail; -- thread.p_next = p_cond->p_head; -- p_cond->p_tail = &thread; -- } -- -- p_cond->num_waiters++; -- -- ABTI_spinlock_release(&p_cond->lock); -- - /* Unlock the mutex that the calling ULT is holding */ - ABTI_mutex_unlock(p_local, p_mutex); -- -- ABTI_xstream *p_local_xstream = ABTI_local_get_xstream_or_null(p_local); -- ABTI_ythread *p_ythread = NULL; -- if (!ABTI_IS_EXT_THREAD_ENABLED || p_local_xstream) { -- p_ythread = ABTI_thread_get_ythread_or_null(p_local_xstream->p_thread); -- } -- while (ABTD_atomic_acquire_load_int(&thread.state) != -- ABT_THREAD_STATE_READY) { -- double cur_time = ABTI_get_wtime(); -- if (cur_time >= tar_time) { -- remove_thread(p_cond, &thread); -- /* Lock the mutex again */ -- ABTI_mutex_lock(&p_local, p_mutex); -- return ABT_ERR_COND_TIMEDOUT; -- } -- if (p_ythread) { -- ABTI_ythread_yield(&p_local_xstream, p_ythread, -- ABT_SYNC_EVENT_TYPE_COND, (void *)p_cond); -- p_local = ABTI_xstream_get_local(p_local_xstream); -- } else { -- ABTD_atomic_pause(); -- } -- } -+ ABT_bool is_timedout = -+ ABTI_waitlist_wait_timedout_and_unlock(&p_local, &p_cond->waitlist, -+ &p_cond->lock, ABT_FALSE, -+ tar_time, -+ ABT_SYNC_EVENT_TYPE_COND, -+ (void *)p_cond); - /* Lock the mutex again */ - ABTI_mutex_lock(&p_local, p_mutex); -- return ABT_SUCCESS; -+ return is_timedout ? ABT_ERR_COND_TIMEDOUT : ABT_SUCCESS; - } - - /** -@@ -248,37 +175,9 @@ int ABT_cond_signal(ABT_cond cond) - ABTI_CHECK_NULL_COND_PTR(p_cond); - - ABTI_spinlock_acquire(&p_cond->lock); -- -- if (p_cond->num_waiters == 0) { -- ABTI_spinlock_release(&p_cond->lock); -- return ABT_SUCCESS; -- } -- -- /* Wake up the first waiting ULT */ -- ABTI_thread *p_thread = p_cond->p_head; -- -- p_cond->num_waiters--; -- if (p_cond->num_waiters == 0) { -- p_cond->p_waiter_mutex = NULL; -- p_cond->p_head = NULL; -- p_cond->p_tail = NULL; -- } else { -- p_thread->p_prev->p_next = p_thread->p_next; -- p_thread->p_next->p_prev = p_thread->p_prev; -- p_cond->p_head = p_thread->p_next; -- } -- p_thread->p_prev = NULL; -- p_thread->p_next = NULL; -- -- ABTI_ythread *p_ythread = ABTI_thread_get_ythread_or_null(p_thread); -- if (p_ythread) { -- ABTI_ythread_set_ready(p_local, p_ythread); -- } else { -- /* When the head is an external thread */ -- ABTD_atomic_release_store_int(&p_thread->state, ABT_THREAD_STATE_READY); -- } -- -+ ABTI_waitlist_signal(p_local, &p_cond->waitlist); - ABTI_spinlock_release(&p_cond->lock); -+ - return ABT_SUCCESS; - } - -@@ -304,3 +203,14 @@ int ABT_cond_broadcast(ABT_cond cond) - ABTI_cond_broadcast(p_local, p_cond); - return ABT_SUCCESS; - } -+ -+/*****************************************************************************/ -+/* Internal static functions */ -+/*****************************************************************************/ -+ -+static inline double convert_timespec_to_sec(const struct timespec *p_ts) -+{ -+ double secs; -+ secs = ((double)p_ts->tv_sec) + 1.0e-9 * ((double)p_ts->tv_nsec); -+ return secs; -+} -diff --git a/src/error.c b/src/error.c -index 5793382..2d2d023 100644 ---- a/src/error.c -+++ b/src/error.c -@@ -44,7 +44,7 @@ int ABT_error_get_str(int err, char *str, size_t *len) - "ABT_ERR_INV_UNIT", - "ABT_ERR_INV_THREAD", - "ABT_ERR_INV_THREAD_ATTR", -- "ABT_ERR_INV_TASK", -+ NULL, /* 18 */ - "ABT_ERR_INV_KEY", - "ABT_ERR_INV_MUTEX", - "ABT_ERR_INV_MUTEX_ATTR", -@@ -63,7 +63,7 @@ int ABT_error_get_str(int err, char *str, size_t *len) - "ABT_ERR_POOL", - "ABT_ERR_UNIT", - "ABT_ERR_THREAD", -- "ABT_ERR_TASK", -+ NULL, /* 37 */ - "ABT_ERR_KEY", - "ABT_ERR_MUTEX", - "ABT_ERR_MUTEX_LOCKED", -@@ -74,14 +74,18 @@ int ABT_error_get_str(int err, char *str, size_t *len) - "ABT_ERR_FUTURE", - "ABT_ERR_BARRIER", - "ABT_ERR_TIMER", -- "ABT_ERR_EVENT", - "ABT_ERR_MIGRATION_TARGET", - "ABT_ERR_MIGRATION_NA", - "ABT_ERR_MISSING_JOIN", -- "ABT_ERR_FEATURE_NA" }; -+ "ABT_ERR_FEATURE_NA", -+ "ABT_ERR_INV_TOOL_CONTEXT", -+ "ABT_ERR_INV_ARG" }; - -- ABTI_CHECK_TRUE(err >= ABT_SUCCESS && err <= ABT_ERR_FEATURE_NA, -- ABT_ERR_OTHER); -+ ABTI_CHECK_TRUE(err >= ABT_SUCCESS && -+ err < (int)(sizeof(err_str) / sizeof(err_str[0])), -+ ABT_ERR_INV_ARG); -+ /* This entry does not exist. */ -+ ABTI_CHECK_TRUE(err_str[err], ABT_ERR_INV_ARG); - if (str) - strcpy(str, err_str[err]); - if (len) -diff --git a/src/eventual.c b/src/eventual.c -index d1d68b1..2c92a47 100644 ---- a/src/eventual.c -+++ b/src/eventual.c -@@ -33,24 +33,24 @@ int ABT_eventual_create(int nbytes, ABT_eventual *neweventual) - { - int abt_errno; - ABTI_eventual *p_eventual; -+ size_t arg_nbytes = nbytes; - - abt_errno = ABTU_malloc(sizeof(ABTI_eventual), (void **)&p_eventual); - ABTI_CHECK_ERROR(abt_errno); - - ABTI_spinlock_clear(&p_eventual->lock); - p_eventual->ready = ABT_FALSE; -- p_eventual->nbytes = nbytes; -- if (nbytes == 0) { -+ p_eventual->nbytes = arg_nbytes; -+ if (arg_nbytes == 0) { - p_eventual->value = NULL; - } else { -- abt_errno = ABTU_malloc(nbytes, &p_eventual->value); -+ abt_errno = ABTU_malloc(arg_nbytes, &p_eventual->value); - if (ABTI_IS_ERROR_CHECK_ENABLED && abt_errno != ABT_SUCCESS) { - ABTU_free(p_eventual); - ABTI_HANDLE_ERROR(abt_errno); - } - } -- p_eventual->p_head = NULL; -- p_eventual->p_tail = NULL; -+ ABTI_waitlist_init(&p_eventual->waitlist); - - *neweventual = ABTI_eventual_get_handle(p_eventual); - return ABT_SUCCESS; -@@ -111,59 +111,16 @@ int ABT_eventual_wait(ABT_eventual eventual, void **value) - - ABTI_spinlock_acquire(&p_eventual->lock); - if (p_eventual->ready == ABT_FALSE) { -- ABTI_ythread *p_ythread = NULL; -- ABTI_thread *p_thread; -- -- ABTI_xstream *p_local_xstream = ABTI_local_get_xstream_or_null(p_local); -- if (!ABTI_IS_EXT_THREAD_ENABLED || p_local_xstream) { -- p_thread = p_local_xstream->p_thread; -- p_ythread = ABTI_thread_get_ythread_or_null(p_thread); -- } -- if (!p_ythread) { -- /* external thread or non-yieldable thread */ -- int abt_errno = -- ABTU_calloc(1, sizeof(ABTI_thread), (void **)&p_thread); -- if (ABTI_IS_ERROR_CHECK_ENABLED && abt_errno != ABT_SUCCESS) { -- ABTI_spinlock_release(&p_eventual->lock); -- ABTI_HANDLE_ERROR(abt_errno); -- } -- p_thread->type = ABTI_THREAD_TYPE_EXT; -- /* use state for synchronization */ -- ABTD_atomic_relaxed_store_int(&p_thread->state, -- ABT_THREAD_STATE_BLOCKED); -- } -- -- p_thread->p_next = NULL; -- if (p_eventual->p_head == NULL) { -- p_eventual->p_head = p_thread; -- p_eventual->p_tail = p_thread; -- } else { -- p_eventual->p_tail->p_next = p_thread; -- p_eventual->p_tail = p_thread; -- } -- -- if (p_ythread) { -- ABTI_ythread_set_blocked(p_ythread); -- -- ABTI_spinlock_release(&p_eventual->lock); -- -- /* Suspend the current ULT */ -- ABTI_ythread_suspend(&p_local_xstream, p_ythread, -- ABT_SYNC_EVENT_TYPE_EVENTUAL, -- (void *)p_eventual); -- } else { -- ABTI_spinlock_release(&p_eventual->lock); -- -- /* External thread is waiting here. */ -- while (ABTD_atomic_acquire_load_int(&p_thread->state) != -- ABT_THREAD_STATE_READY) -- ; -- if (p_thread->type == ABTI_THREAD_TYPE_EXT) -- ABTU_free(p_thread); -- } -+ ABTI_waitlist_wait_and_unlock(&p_local, &p_eventual->waitlist, -+ &p_eventual->lock, ABT_FALSE, -+ ABT_SYNC_EVENT_TYPE_EVENTUAL, -+ (void *)p_eventual); - } else { - ABTI_spinlock_release(&p_eventual->lock); - } -+ /* This value is updated outside the critical section, but it is okay since -+ * the "pointer" to the memory buffer is constant and there is no way to -+ * avoid updating this memory buffer by ABT_eventual_set() etc. */ - if (value) - *value = p_eventual->value; - return ABT_SUCCESS; -@@ -184,11 +141,11 @@ int ABT_eventual_wait(ABT_eventual eventual, void **value) - * @return Error code - * @retval ABT_SUCCESS on success - */ --int ABT_eventual_test(ABT_eventual eventual, void **value, int *is_ready) -+int ABT_eventual_test(ABT_eventual eventual, void **value, ABT_bool *is_ready) - { - ABTI_eventual *p_eventual = ABTI_eventual_get_ptr(eventual); - ABTI_CHECK_NULL_EVENTUAL_PTR(p_eventual); -- int flag = ABT_FALSE; -+ ABT_bool flag = ABT_FALSE; - - ABTI_spinlock_acquire(&p_eventual->lock); - if (p_eventual->ready != ABT_FALSE) { -@@ -224,45 +181,16 @@ int ABT_eventual_set(ABT_eventual eventual, void *value, int nbytes) - ABTI_local *p_local = ABTI_local_get_local(); - ABTI_eventual *p_eventual = ABTI_eventual_get_ptr(eventual); - ABTI_CHECK_NULL_EVENTUAL_PTR(p_eventual); -- ABTI_CHECK_TRUE(nbytes <= p_eventual->nbytes, ABT_ERR_INV_EVENTUAL); -+ size_t arg_nbytes = nbytes; -+ ABTI_CHECK_TRUE(arg_nbytes <= p_eventual->nbytes, ABT_ERR_INV_EVENTUAL); - - ABTI_spinlock_acquire(&p_eventual->lock); - - p_eventual->ready = ABT_TRUE; - if (p_eventual->value) -- memcpy(p_eventual->value, value, nbytes); -- -- if (p_eventual->p_head == NULL) { -- ABTI_spinlock_release(&p_eventual->lock); -- return ABT_SUCCESS; -- } -- -+ memcpy(p_eventual->value, value, arg_nbytes); - /* Wake up all waiting ULTs */ -- ABTI_thread *p_head = p_eventual->p_head; -- ABTI_thread *p_thread = p_head; -- while (1) { -- ABTI_thread *p_next = p_thread->p_next; -- p_thread->p_next = NULL; -- -- ABTI_ythread *p_ythread = ABTI_thread_get_ythread_or_null(p_thread); -- if (p_ythread) { -- ABTI_ythread_set_ready(p_local, p_ythread); -- } else { -- /* When the head is an external thread */ -- ABTD_atomic_release_store_int(&p_thread->state, -- ABT_THREAD_STATE_READY); -- } -- -- /* Next ULT */ -- if (p_next != NULL) { -- p_thread = p_next; -- } else { -- break; -- } -- } -- -- p_eventual->p_head = NULL; -- p_eventual->p_tail = NULL; -+ ABTI_waitlist_broadcast(p_local, &p_eventual->waitlist); - - ABTI_spinlock_release(&p_eventual->lock); - return ABT_SUCCESS; -diff --git a/src/futures.c b/src/futures.c -index 8f3c9c5..d408b06 100644 ---- a/src/futures.c -+++ b/src/futures.c -@@ -58,21 +58,21 @@ int ABT_future_create(uint32_t compartments, void (*cb_func)(void **arg), - { - int abt_errno; - ABTI_future *p_future; -+ size_t arg_compartments = compartments; - - abt_errno = ABTU_malloc(sizeof(ABTI_future), (void **)&p_future); - ABTI_CHECK_ERROR(abt_errno); - ABTI_spinlock_clear(&p_future->lock); -- ABTD_atomic_relaxed_store_uint32(&p_future->counter, 0); -- p_future->compartments = compartments; -- abt_errno = -- ABTU_malloc(compartments * sizeof(void *), (void **)&p_future->array); -+ ABTD_atomic_relaxed_store_size(&p_future->counter, 0); -+ p_future->compartments = arg_compartments; -+ abt_errno = ABTU_malloc(arg_compartments * sizeof(void *), -+ (void **)&p_future->array); - if (ABTI_IS_ERROR_CHECK_ENABLED && abt_errno != ABT_SUCCESS) { - ABTU_free(p_future); - ABTI_HANDLE_ERROR(abt_errno); - } - p_future->p_callback = cb_func; -- p_future->p_head = NULL; -- p_future->p_tail = NULL; -+ ABTI_waitlist_init(&p_future->waitlist); - - *newfuture = ABTI_future_get_handle(p_future); - return ABT_SUCCESS; -@@ -129,57 +129,12 @@ int ABT_future_wait(ABT_future future) - ABTI_CHECK_NULL_FUTURE_PTR(p_future); - - ABTI_spinlock_acquire(&p_future->lock); -- if (ABTD_atomic_relaxed_load_uint32(&p_future->counter) < -+ if (ABTD_atomic_relaxed_load_size(&p_future->counter) < - p_future->compartments) { -- ABTI_ythread *p_ythread = NULL; -- ABTI_thread *p_thread; -- -- ABTI_xstream *p_local_xstream = ABTI_local_get_xstream_or_null(p_local); -- if (!ABTI_IS_EXT_THREAD_ENABLED || p_local_xstream) { -- p_thread = p_local_xstream->p_thread; -- p_ythread = ABTI_thread_get_ythread_or_null(p_thread); -- } -- if (!p_ythread) { -- /* external thread */ -- int abt_errno = -- ABTU_calloc(1, sizeof(ABTI_thread), (void **)&p_thread); -- if (ABTI_IS_ERROR_CHECK_ENABLED && abt_errno != ABT_SUCCESS) { -- ABTI_spinlock_release(&p_future->lock); -- ABTI_HANDLE_ERROR(abt_errno); -- } -- p_thread->type = ABTI_THREAD_TYPE_EXT; -- /* use state for synchronization */ -- ABTD_atomic_relaxed_store_int(&p_thread->state, -- ABT_THREAD_STATE_BLOCKED); -- } -- -- p_thread->p_next = NULL; -- if (p_future->p_head == NULL) { -- p_future->p_head = p_thread; -- p_future->p_tail = p_thread; -- } else { -- p_future->p_tail->p_next = p_thread; -- p_future->p_tail = p_thread; -- } -- -- if (p_ythread) { -- ABTI_ythread_set_blocked(p_ythread); -- -- ABTI_spinlock_release(&p_future->lock); -- -- /* Suspend the current ULT */ -- ABTI_ythread_suspend(&p_local_xstream, p_ythread, -- ABT_SYNC_EVENT_TYPE_FUTURE, (void *)p_future); -- -- } else { -- ABTI_spinlock_release(&p_future->lock); -- -- /* External thread is waiting here. */ -- while (ABTD_atomic_acquire_load_int(&p_thread->state) != -- ABT_THREAD_STATE_READY) -- ; -- ABTU_free(p_thread); -- } -+ ABTI_waitlist_wait_and_unlock(&p_local, &p_future->waitlist, -+ &p_future->lock, ABT_FALSE, -+ ABT_SYNC_EVENT_TYPE_FUTURE, -+ (void *)p_future); - } else { - ABTI_spinlock_release(&p_future->lock); - } -@@ -203,7 +158,7 @@ int ABT_future_test(ABT_future future, ABT_bool *flag) - ABTI_future *p_future = ABTI_future_get_ptr(future); - ABTI_CHECK_NULL_FUTURE_PTR(p_future); - -- uint32_t counter = ABTD_atomic_acquire_load_uint32(&p_future->counter); -+ size_t counter = ABTD_atomic_acquire_load_size(&p_future->counter); - *flag = (counter == p_future->compartments) ? ABT_TRUE : ABT_FALSE; - return ABT_SUCCESS; - } -@@ -233,51 +188,25 @@ int ABT_future_set(ABT_future future, void *value) - - ABTI_spinlock_acquire(&p_future->lock); - -- int counter = ABTD_atomic_relaxed_load_uint32(&p_future->counter); -+ size_t counter = ABTD_atomic_relaxed_load_size(&p_future->counter); -+ size_t compartments = p_future->compartments; - #ifndef ABT_CONFIG_DISABLE_ERROR_CHECK -- if (counter >= p_future->compartments) { -+ if (counter >= compartments) { - ABTI_spinlock_release(&p_future->lock); - ABTI_HANDLE_ERROR(ABT_ERR_FUTURE); - } - #endif - p_future->array[counter] = value; - counter++; -- ABTD_atomic_release_store_uint32(&p_future->counter, counter); -- -- if (counter == p_future->compartments) { -- if (p_future->p_callback != NULL) -- (*p_future->p_callback)(p_future->array); -- -- if (p_future->p_head == NULL) { -- ABTI_spinlock_release(&p_future->lock); -- return ABT_SUCCESS; -- } -- -- /* Wake up all waiting ULTs */ -- ABTI_thread *p_head = p_future->p_head; -- ABTI_thread *p_thread = p_head; -- while (1) { -- ABTI_thread *p_next = p_thread->p_next; -- p_thread->p_next = NULL; -+ /* Call a callback function before setting the counter. */ -+ if (counter == compartments && p_future->p_callback != NULL) { -+ (*p_future->p_callback)(p_future->array); -+ } - -- ABTI_ythread *p_ythread = ABTI_thread_get_ythread_or_null(p_thread); -- if (p_ythread) { -- ABTI_ythread_set_ready(p_local, p_ythread); -- } else { -- /* When the head is an external thread */ -- ABTD_atomic_release_store_int(&p_thread->state, -- ABT_THREAD_STATE_READY); -- } -+ ABTD_atomic_release_store_size(&p_future->counter, counter); - -- /* Next ULT */ -- if (p_next != NULL) { -- p_thread = p_next; -- } else { -- break; -- } -- } -- p_future->p_head = NULL; -- p_future->p_tail = NULL; -+ if (counter == compartments) { -+ ABTI_waitlist_broadcast(p_local, &p_future->waitlist); - } - - ABTI_spinlock_release(&p_future->lock); -@@ -302,7 +231,7 @@ int ABT_future_reset(ABT_future future) - ABTI_CHECK_NULL_FUTURE_PTR(p_future); - - ABTI_spinlock_acquire(&p_future->lock); -- ABTD_atomic_release_store_uint32(&p_future->counter, 0); -+ ABTD_atomic_release_store_size(&p_future->counter, 0); - ABTI_spinlock_release(&p_future->lock); - return ABT_SUCCESS; - } -diff --git a/src/include/Makefile.mk b/src/include/Makefile.mk -index 2410cf7..382a888 100644 ---- a/src/include/Makefile.mk -+++ b/src/include/Makefile.mk -@@ -38,8 +38,8 @@ noinst_HEADERS = \ - include/abti_timer.h \ - include/abti_thread.h \ - include/abti_thread_attr.h \ -+ include/abti_waitlist.h \ - include/abti_tool.h \ - include/abti_valgrind.h \ - include/abti_ythread.h \ -- include/abti_ythread_htable.h \ - include/abtu.h -diff --git a/src/include/abt.h.in b/src/include/abt.h.in -index 7a9880c..02910cb 100644 ---- a/src/include/abt.h.in -+++ b/src/include/abt.h.in -@@ -91,6 +91,7 @@ extern "C" { - #define ABT_ERR_INV_TIMER 27 /* Invalid timer */ - #define ABT_ERR_INV_QUERY_KIND 28 /* Invalid query kind */ - #define ABT_ERR_INV_TOOL_CONTEXT 52 /* Invalid tool context */ -+#define ABT_ERR_INV_ARG 53 /* Invalid argument */ - #define ABT_ERR_XSTREAM 29 /* ES-related error */ - #define ABT_ERR_XSTREAM_STATE 30 /* ES state error */ - #define ABT_ERR_XSTREAM_BARRIER 31 /* ES barrier-related error */ -@@ -115,7 +116,6 @@ extern "C" { - #define ABT_ERR_MISSING_JOIN 50 /* An ES or more did not join */ - #define ABT_ERR_FEATURE_NA 51 /* Feature not available */ - -- - /* Constants */ - enum ABT_xstream_state { - ABT_XSTREAM_STATE_RUNNING, -@@ -222,6 +222,12 @@ enum ABT_info_query_kind { - ABT_INFO_QUERY_KIND_DEFAULT_SCHED_SLEEP_NSEC, - /* Whether the tool interface is enabled or not */ - ABT_INFO_QUERY_KIND_ENABLED_TOOL, -+ /* Whether fcontext is used for context switch or not */ -+ ABT_INFO_QUERY_KIND_FCONTEXT, -+ /* Whether dynamic promotion is used for context switch or not */ -+ ABT_INFO_QUERY_KIND_DYNAMIC_PROMOTION, -+ /* Whether the stack unwinding feature is enabled or not */ -+ ABT_INFO_QUERY_KIND_ENABLED_STACK_UNWIND, - }; - - enum ABT_tool_query_kind { -@@ -753,7 +759,7 @@ int ABT_rwlock_unlock(ABT_rwlock rwlock) ABT_API_PUBLIC; - int ABT_eventual_create(int nbytes, ABT_eventual *neweventual) ABT_API_PUBLIC; - int ABT_eventual_free(ABT_eventual *eventual) ABT_API_PUBLIC; - int ABT_eventual_wait(ABT_eventual eventual, void **value) ABT_API_PUBLIC; --int ABT_eventual_test(ABT_eventual eventual, void **value, int *is_ready) ABT_API_PUBLIC; -+int ABT_eventual_test(ABT_eventual eventual, void **value, ABT_bool *is_ready) ABT_API_PUBLIC; - int ABT_eventual_set(ABT_eventual eventual, void *value, int nbytes) ABT_API_PUBLIC; - int ABT_eventual_reset(ABT_eventual eventual) ABT_API_PUBLIC; - -diff --git a/src/include/abtd.h b/src/include/abtd.h -index 8b57293..76af062 100644 ---- a/src/include/abtd.h -+++ b/src/include/abtd.h -@@ -51,6 +51,8 @@ void ABTD_xstream_context_free(ABTD_xstream_context *p_ctx); - void ABTD_xstream_context_join(ABTD_xstream_context *p_ctx); - void ABTD_xstream_context_revive(ABTD_xstream_context *p_ctx); - void ABTD_xstream_context_set_self(ABTD_xstream_context *p_ctx); -+void ABTD_xstream_context_print(ABTD_xstream_context *p_ctx, FILE *p_os, -+ int indent); - - /* ES Affinity */ - void ABTD_affinity_init(const char *affinity_str); -@@ -65,11 +67,11 @@ void ABTD_affinity_cpuset_destroy(ABTD_affinity_cpuset *p_cpuset); - - /* ES Affinity Parser */ - typedef struct ABTD_affinity_id_list { -- int num; -+ uint32_t num; - int *ids; /* id here can be negative. */ - } ABTD_affinity_id_list; - typedef struct ABTD_affinity_parser_list { -- int num; -+ uint32_t num; - ABTD_affinity_id_list **p_id_lists; - } ABTD_affinity_list; - ABTD_affinity_list *ABTD_affinity_list_create(const char *affinity_str); -diff --git a/src/include/abtd_atomic.h b/src/include/abtd_atomic.h -index 74475bc..2307d6d 100644 ---- a/src/include/abtd_atomic.h -+++ b/src/include/abtd_atomic.h -@@ -16,6 +16,10 @@ typedef struct ABTD_atomic_int { - int val; - } ABTD_atomic_int; - -+typedef struct ABTD_atomic_size { -+ size_t val; -+} ABTD_atomic_size; -+ - typedef struct ABTD_atomic_int32 { - int32_t val; - } ABTD_atomic_int32; -@@ -44,6 +48,10 @@ typedef struct ABTD_atomic_ptr { - { \ - (val) \ - } -+#define ABTD_ATOMIC_SIZE_STATIC_INITIALIZER(val) \ -+ { \ -+ (val) \ -+ } - #define ABTD_ATOMIC_INT32_STATIC_INITIALIZER(val) \ - { \ - (val) \ -@@ -78,6 +86,20 @@ static inline int ABTDI_atomic_val_cas_int(ABTD_atomic_int *ptr, int oldv, - #endif - } - -+static inline size_t ABTDI_atomic_val_cas_size(ABTD_atomic_size *ptr, -+ size_t oldv, size_t newv, -+ int weak) -+{ -+#ifdef ABT_CONFIG_HAVE_ATOMIC_BUILTIN -+ size_t tmp_oldv = oldv; -+ int ret = __atomic_compare_exchange_n(&ptr->val, &oldv, newv, weak, -+ __ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE); -+ return ret ? tmp_oldv : oldv; -+#else -+ return __sync_val_compare_and_swap(&ptr->val, oldv, newv); -+#endif -+} -+ - static inline int32_t ABTDI_atomic_val_cas_int32(ABTD_atomic_int32 *ptr, - int32_t oldv, int32_t newv, - int weak) -@@ -158,6 +180,17 @@ static inline int ABTDI_atomic_bool_cas_int(ABTD_atomic_int *ptr, int oldv, - #endif - } - -+static inline int ABTDI_atomic_bool_cas_size(ABTD_atomic_size *ptr, size_t oldv, -+ size_t newv, int weak) -+{ -+#ifdef ABT_CONFIG_HAVE_ATOMIC_BUILTIN -+ return __atomic_compare_exchange_n(&ptr->val, &oldv, newv, weak, -+ __ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE); -+#else -+ return __sync_bool_compare_and_swap(&ptr->val, oldv, newv); -+#endif -+} -+ - static inline int ABTDI_atomic_bool_cas_int32(ABTD_atomic_int32 *ptr, - int32_t oldv, int32_t newv, - int weak) -@@ -223,6 +256,12 @@ static inline int ABTD_atomic_val_cas_weak_int(ABTD_atomic_int *ptr, int oldv, - return ABTDI_atomic_val_cas_int(ptr, oldv, newv, 1); - } - -+static inline size_t ABTD_atomic_val_cas_weak_size(ABTD_atomic_size *ptr, -+ size_t oldv, size_t newv) -+{ -+ return ABTDI_atomic_val_cas_size(ptr, oldv, newv, 1); -+} -+ - static inline int32_t ABTD_atomic_val_cas_weak_int32(ABTD_atomic_int32 *ptr, - int32_t oldv, int32_t newv) - { -@@ -261,6 +300,12 @@ static inline int ABTD_atomic_val_cas_strong_int(ABTD_atomic_int *ptr, int oldv, - return ABTDI_atomic_val_cas_int(ptr, oldv, newv, 0); - } - -+static inline size_t ABTD_atomic_val_cas_strong_size(ABTD_atomic_size *ptr, -+ size_t oldv, size_t newv) -+{ -+ return ABTDI_atomic_val_cas_size(ptr, oldv, newv, 0); -+} -+ - static inline int32_t ABTD_atomic_val_cas_strong_int32(ABTD_atomic_int32 *ptr, - int32_t oldv, - int32_t newv) -@@ -301,6 +346,12 @@ static inline int ABTD_atomic_bool_cas_weak_int(ABTD_atomic_int *ptr, int oldv, - return ABTDI_atomic_bool_cas_int(ptr, oldv, newv, 1); - } - -+static inline int ABTD_atomic_bool_cas_weak_size(ABTD_atomic_size *ptr, -+ size_t oldv, size_t newv) -+{ -+ return ABTDI_atomic_bool_cas_size(ptr, oldv, newv, 1); -+} -+ - static inline int ABTD_atomic_bool_cas_weak_int32(ABTD_atomic_int32 *ptr, - int32_t oldv, int32_t newv) - { -@@ -337,6 +388,12 @@ static inline int ABTD_atomic_bool_cas_strong_int(ABTD_atomic_int *ptr, - return ABTDI_atomic_bool_cas_int(ptr, oldv, newv, 0); - } - -+static inline int ABTD_atomic_bool_cas_strong_size(ABTD_atomic_size *ptr, -+ size_t oldv, size_t newv) -+{ -+ return ABTDI_atomic_bool_cas_size(ptr, oldv, newv, 0); -+} -+ - static inline int ABTD_atomic_bool_cas_strong_int32(ABTD_atomic_int32 *ptr, - int32_t oldv, int32_t newv) - { -@@ -378,6 +435,15 @@ static inline int ABTD_atomic_fetch_add_int(ABTD_atomic_int *ptr, int v) - #endif - } - -+static inline size_t ABTD_atomic_fetch_add_size(ABTD_atomic_size *ptr, size_t v) -+{ -+#ifdef ABT_CONFIG_HAVE_ATOMIC_BUILTIN -+ return __atomic_fetch_add(&ptr->val, v, __ATOMIC_ACQ_REL); -+#else -+ return __sync_fetch_and_add(&ptr->val, v); -+#endif -+} -+ - static inline int32_t ABTD_atomic_fetch_add_int32(ABTD_atomic_int32 *ptr, - int32_t v) - { -@@ -427,6 +493,15 @@ static inline int ABTD_atomic_fetch_sub_int(ABTD_atomic_int *ptr, int v) - #endif - } - -+static inline size_t ABTD_atomic_fetch_sub_size(ABTD_atomic_size *ptr, size_t v) -+{ -+#ifdef ABT_CONFIG_HAVE_ATOMIC_BUILTIN -+ return __atomic_fetch_sub(&ptr->val, v, __ATOMIC_ACQ_REL); -+#else -+ return __sync_fetch_and_sub(&ptr->val, v); -+#endif -+} -+ - static inline int32_t ABTD_atomic_fetch_sub_int32(ABTD_atomic_int32 *ptr, - int32_t v) - { -@@ -476,6 +551,15 @@ static inline int ABTD_atomic_fetch_and_int(ABTD_atomic_int *ptr, int v) - #endif - } - -+static inline size_t ABTD_atomic_fetch_and_size(ABTD_atomic_size *ptr, size_t v) -+{ -+#ifdef ABT_CONFIG_HAVE_ATOMIC_BUILTIN -+ return __atomic_fetch_and(&ptr->val, v, __ATOMIC_ACQ_REL); -+#else -+ return __sync_fetch_and_and(&ptr->val, v); -+#endif -+} -+ - static inline int32_t ABTD_atomic_fetch_and_int32(ABTD_atomic_int32 *ptr, - int32_t v) - { -@@ -525,6 +609,15 @@ static inline int ABTD_atomic_fetch_or_int(ABTD_atomic_int *ptr, int v) - #endif - } - -+static inline size_t ABTD_atomic_fetch_or_size(ABTD_atomic_size *ptr, size_t v) -+{ -+#ifdef ABT_CONFIG_HAVE_ATOMIC_BUILTIN -+ return __atomic_fetch_or(&ptr->val, v, __ATOMIC_ACQ_REL); -+#else -+ return __sync_fetch_and_or(&ptr->val, v); -+#endif -+} -+ - static inline int32_t ABTD_atomic_fetch_or_int32(ABTD_atomic_int32 *ptr, - int32_t v) - { -@@ -574,6 +667,15 @@ static inline int ABTD_atomic_fetch_xor_int(ABTD_atomic_int *ptr, int v) - #endif - } - -+static inline size_t ABTD_atomic_fetch_xor_size(ABTD_atomic_size *ptr, size_t v) -+{ -+#ifdef ABT_CONFIG_HAVE_ATOMIC_BUILTIN -+ return __atomic_fetch_xor(&ptr->val, v, __ATOMIC_ACQ_REL); -+#else -+ return __sync_fetch_and_xor(&ptr->val, v); -+#endif -+} -+ - static inline int32_t ABTD_atomic_fetch_xor_int32(ABTD_atomic_int32 *ptr, - int32_t v) - { -@@ -671,6 +773,19 @@ static inline int ABTD_atomic_relaxed_load_int(const ABTD_atomic_int *ptr) - #endif - } - -+static inline size_t ABTD_atomic_relaxed_load_size(const ABTD_atomic_size *ptr) -+{ -+#ifdef ABT_CONFIG_HAVE_ATOMIC_BUILTIN -+#ifndef __SUNPRO_C -+ return __atomic_load_n(&ptr->val, __ATOMIC_RELAXED); -+#else -+ return __atomic_load_n((size_t *)&ptr->val, __ATOMIC_RELAXED); -+#endif -+#else -+ return *(volatile size_t *)&ptr->val; -+#endif -+} -+ - static inline int32_t - ABTD_atomic_relaxed_load_int32(const ABTD_atomic_int32 *ptr) - { -@@ -776,6 +891,22 @@ static inline int ABTD_atomic_acquire_load_int(const ABTD_atomic_int *ptr) - #endif - } - -+static inline size_t ABTD_atomic_acquire_load_size(const ABTD_atomic_size *ptr) -+{ -+#ifdef ABT_CONFIG_HAVE_ATOMIC_BUILTIN -+#ifndef __SUNPRO_C -+ return __atomic_load_n(&ptr->val, __ATOMIC_ACQUIRE); -+#else -+ return __atomic_load_n((size_t *)&ptr->val, __ATOMIC_ACQUIRE); -+#endif -+#else -+ __sync_synchronize(); -+ size_t val = *(volatile size_t *)&ptr->val; -+ __sync_synchronize(); -+ return val; -+#endif -+} -+ - static inline int32_t - ABTD_atomic_acquire_load_int32(const ABTD_atomic_int32 *ptr) - { -@@ -871,6 +1002,16 @@ static inline void ABTD_atomic_relaxed_store_int(ABTD_atomic_int *ptr, int val) - #endif - } - -+static inline void ABTD_atomic_relaxed_store_size(ABTD_atomic_size *ptr, -+ size_t val) -+{ -+#ifdef ABT_CONFIG_HAVE_ATOMIC_BUILTIN -+ __atomic_store_n(&ptr->val, val, __ATOMIC_RELAXED); -+#else -+ *(volatile size_t *)&ptr->val = val; -+#endif -+} -+ - static inline void ABTD_atomic_relaxed_store_int32(ABTD_atomic_int32 *ptr, - int32_t val) - { -@@ -932,6 +1073,18 @@ static inline void ABTD_atomic_release_store_int(ABTD_atomic_int *ptr, int val) - #endif - } - -+static inline void ABTD_atomic_release_store_size(ABTD_atomic_size *ptr, -+ size_t val) -+{ -+#ifdef ABT_CONFIG_HAVE_ATOMIC_BUILTIN -+ __atomic_store_n(&ptr->val, val, __ATOMIC_RELEASE); -+#else -+ __sync_synchronize(); -+ *(volatile size_t *)&ptr->val = val; -+ __sync_synchronize(); -+#endif -+} -+ - static inline void ABTD_atomic_release_store_int32(ABTD_atomic_int32 *ptr, - int32_t val) - { -@@ -1005,6 +1158,19 @@ static inline int ABTD_atomic_exchange_int(ABTD_atomic_int *ptr, int v) - #endif - } - -+static inline size_t ABTD_atomic_exchange_size(ABTD_atomic_size *ptr, size_t v) -+{ -+#ifdef ABT_CONFIG_HAVE_ATOMIC_BUILTIN -+ return __atomic_exchange_n(&ptr->val, v, __ATOMIC_ACQ_REL); -+#else -+ size_t val; -+ do { -+ val = ABTD_atomic_acquire_load_size(ptr); -+ } while (!ABTD_atomic_bool_cas_weak_size(ptr, val, v)); -+ return val; -+#endif -+} -+ - static inline int32_t ABTD_atomic_exchange_int32(ABTD_atomic_int32 *ptr, - int32_t v) - { -diff --git a/src/include/abtd_context.h b/src/include/abtd_context.h -index 32a3b38..f598c8f 100644 ---- a/src/include/abtd_context.h -+++ b/src/include/abtd_context.h -@@ -15,6 +15,11 @@ - #include - #endif - -+#ifdef ABT_CONFIG_ENABLE_STACK_UNWIND -+/* Peek context is needed only for stack unwinding. */ -+#define ABT_CONFIG_ENABLE_PEEK_CONTEXT -+#endif -+ - typedef struct ABTD_ythread_context ABTD_ythread_context; - - typedef struct ABTD_ythread_context_atomic_ptr { -@@ -47,16 +52,7 @@ static inline void ABTD_atomic_release_store_ythread_context_ptr( - ABTD_atomic_release_store_ptr(&ptr->val, (void *)p_ctx); - } - --struct ABTD_ythread_context { -- void *p_ctx; /* actual context of fcontext, or a -- * pointer to uctx */ -- ABTD_ythread_context_atomic_ptr p_link; /* pointer to scheduler context */ --#ifndef ABT_CONFIG_USE_FCONTEXT -- ucontext_t uctx; /* ucontext entity pointed by p_ctx */ -- void (*f_uctx_thread)(void *); /* root function called by ucontext */ -- void *p_uctx_arg; /* argument for root function */ --#endif --}; -+struct ABTD_ythread_context; - - static void ABTD_ythread_context_make(ABTD_ythread_context *p_ctx, void *sp, - size_t size, void (*thread_func)(void *)); -@@ -71,6 +67,11 @@ static void ABTD_ythread_context_init_and_call(ABTD_ythread_context *p_ctx, - void (*thread_func)(void *), - void *arg); - #endif -+#ifdef ABT_CONFIG_ENABLE_PEEK_CONTEXT -+static inline void ABTD_ythread_context_peek(ABTD_ythread_context *p_ctx, -+ void (*peek_func)(void *), -+ void *arg); -+#endif - - void ABTD_ythread_print_context(ABTI_ythread *p_ythread, FILE *p_os, - int indent); -diff --git a/src/include/abtd_fcontext.h b/src/include/abtd_fcontext.h -index ba48a89..3787620 100644 ---- a/src/include/abtd_fcontext.h -+++ b/src/include/abtd_fcontext.h -@@ -23,25 +23,89 @@ void init_and_call_fcontext(void *p_arg, void (*f_thread)(void *), - void *p_stacktop, fcontext_t *old); - #endif - -+#if defined(ABT_CONFIG_ENABLE_PEEK_CONTEXT) && defined(__x86_64__) -+/* We implement peek_fcontext only for x86-64. */ -+void peek_fcontext(fcontext_t new, void (*peek_func)(void *), -+ void *arg) ABT_API_PRIVATE; -+#define ABTD_SUPPORT_PEEK_FCONTEXT 1 -+#endif /* defined(ABT_CONFIG_ENABLE_PEEK_CONTEXT) && defined(__x86_64__) */ -+ -+struct ABTD_ythread_context { -+ void *p_ctx; /* actual context of fcontext, or a -+ * pointer to uctx */ -+ ABTD_ythread_context_atomic_ptr p_link; /* pointer to scheduler context */ -+#if defined(ABT_CONFIG_ENABLE_PEEK_CONTEXT) && \ -+ !defined(ABTD_CONTEXT_SUPPORT_PEEK_FCONTEXT) -+ void (*thread_func)(void *); -+ void *arg; -+ void (*peek_func)(void *); -+ void *peek_arg; -+ void *p_peek_ctx; -+ ABT_bool is_peeked; -+#endif -+}; -+ -+#if defined(ABT_CONFIG_ENABLE_PEEK_CONTEXT) && \ -+ !defined(ABTD_CONTEXT_SUPPORT_PEEK_FCONTEXT) -+static inline void ABTDI_fcontext_check_peeked(ABTD_ythread_context *p_self) -+{ -+ /* Check if this thread is called only for peeked */ -+ while (ABTU_unlikely(p_self->is_peeked)) { -+ p_self->peek_func(p_self->peek_arg); -+ /* Reset the flag. */ -+ p_self->is_peeked = ABT_FALSE; -+ jump_fcontext(&p_self->p_ctx, p_self->p_peek_ctx, NULL); -+ } -+} -+ -+static inline void ABTDI_fcontext_wrapper(void *arg) -+{ -+ ABTD_ythread_context *p_self = (ABTD_ythread_context *)arg; -+ ABTDI_fcontext_check_peeked(p_self); -+ p_self->thread_func(p_self->arg); -+} -+#endif -+ - static inline void ABTD_ythread_context_make(ABTD_ythread_context *p_ctx, - void *sp, size_t size, - void (*thread_func)(void *)) - { -+#if defined(ABT_CONFIG_ENABLE_PEEK_CONTEXT) && \ -+ !defined(ABTD_CONTEXT_SUPPORT_PEEK_FCONTEXT) -+ p_ctx->thread_func = thread_func; -+ p_ctx->is_peeked = ABT_FALSE; -+ p_ctx->p_ctx = make_fcontext(sp, size, ABTDI_fcontext_wrapper); -+#else - p_ctx->p_ctx = make_fcontext(sp, size, thread_func); -+#endif - } - - static inline void ABTD_ythread_context_jump(ABTD_ythread_context *p_old, - ABTD_ythread_context *p_new, - void *arg) - { -+#if defined(ABT_CONFIG_ENABLE_PEEK_CONTEXT) && \ -+ !defined(ABTD_CONTEXT_SUPPORT_PEEK_FCONTEXT) -+ p_new->arg = arg; -+ p_old->is_peeked = ABT_FALSE; -+ jump_fcontext(&p_old->p_ctx, p_new->p_ctx, p_new); -+ ABTDI_fcontext_check_peeked(p_old); -+#else - jump_fcontext(&p_old->p_ctx, p_new->p_ctx, arg); -+#endif - } - - ABTU_noreturn static inline void - ABTD_ythread_context_take(ABTD_ythread_context *p_old, - ABTD_ythread_context *p_new, void *arg) - { -+#if defined(ABT_CONFIG_ENABLE_PEEK_CONTEXT) && \ -+ !defined(ABTD_CONTEXT_SUPPORT_PEEK_FCONTEXT) -+ p_new->arg = arg; -+ take_fcontext(&p_old->p_ctx, p_new->p_ctx, p_new); -+#else - take_fcontext(&p_old->p_ctx, p_new->p_ctx, arg); -+#endif - ABTU_unreachable(); - } - -@@ -50,8 +114,31 @@ static inline void - ABTD_ythread_context_init_and_call(ABTD_ythread_context *p_ctx, void *sp, - void (*thread_func)(void *), void *arg) - { -+#if defined(ABT_CONFIG_ENABLE_PEEK_CONTEXT) && \ -+ !defined(ABTD_CONTEXT_SUPPORT_PEEK_FCONTEXT) -+ p_ctx->is_peeked = ABT_FALSE; - init_and_call_fcontext(arg, thread_func, sp, &p_ctx->p_ctx); -+ ABTDI_fcontext_check_peeked(p_ctx); -+#else -+ init_and_call_fcontext(arg, thread_func, sp, &p_ctx->p_ctx); -+#endif - } - #endif - -+#ifdef ABT_CONFIG_ENABLE_PEEK_CONTEXT -+static inline void ABTD_ythread_context_peek(ABTD_ythread_context *p_ctx, -+ void (*peek_func)(void *), -+ void *arg) -+{ -+#ifdef ABTD_CONTEXT_SUPPORT_PEEK_FCONTEXT -+ peek_fcontext(p_ctx->p_ctx, peek_func, *arg); -+#else -+ p_ctx->peek_arg = arg; -+ p_ctx->peek_func = peek_func; -+ p_ctx->is_peeked = ABT_TRUE; -+ jump_fcontext(&p_ctx->p_peek_ctx, p_ctx->p_ctx, p_ctx); -+#endif -+} -+#endif /*!ABT_CONFIG_ENABLE_PEEK_CONTEXT */ -+ - #endif /* ABTD_FCONTEXT_H_INCLUDED */ -diff --git a/src/include/abtd_ucontext.h b/src/include/abtd_ucontext.h -index 4e1646d..e36edc4 100644 ---- a/src/include/abtd_ucontext.h -+++ b/src/include/abtd_ucontext.h -@@ -6,6 +6,35 @@ - #ifndef ABTD_UCONTEXT_H_INCLUDED - #define ABTD_UCONTEXT_H_INCLUDED - -+struct ABTD_ythread_context { -+ void *p_ctx; /* actual context of fcontext, or a -+ * pointer to uctx */ -+ ABTD_ythread_context_atomic_ptr p_link; /* pointer to scheduler context */ -+ ucontext_t uctx; /* ucontext entity pointed by p_ctx */ -+ void (*f_uctx_thread)(void *); /* root function called by ucontext */ -+ void *p_uctx_arg; /* argument for root function */ -+#ifdef ABT_CONFIG_ENABLE_PEEK_CONTEXT -+ void (*peek_func)(void *); -+ void *peek_arg; -+ ucontext_t *p_peek_uctx; -+ ABT_bool is_peeked; -+#endif -+}; -+ -+#ifdef ABT_CONFIG_ENABLE_PEEK_CONTEXT -+static inline void ABTDI_ucontext_check_peeked(ABTD_ythread_context *p_self) -+{ -+ /* Check if this thread is called only for peeked */ -+ while (ABTU_unlikely(p_self->is_peeked)) { -+ p_self->peek_func(p_self->peek_arg); -+ /* Reset the flag. */ -+ p_self->is_peeked = ABT_FALSE; -+ int ret = swapcontext(&p_self->uctx, p_self->p_peek_uctx); -+ ABTI_ASSERT(ret == 0); /* Fatal. */ -+ } -+} -+#endif -+ - static void ABTD_ucontext_wrapper(int arg1, int arg2) - { - ABTD_ythread_context *p_self; -@@ -17,6 +46,11 @@ static void ABTD_ucontext_wrapper(int arg1, int arg2) - #else - #error "Unknown pointer size." - #endif -+ -+#ifdef ABT_CONFIG_ENABLE_PEEK_CONTEXT -+ ABTDI_ucontext_check_peeked(p_self); -+#endif -+ - p_self->f_uctx_thread(p_self->p_uctx_arg); - /* ABTD_ythread_context_jump or take must be called at the end of - * f_uctx_thread, */ -@@ -49,16 +83,25 @@ static inline void ABTD_ythread_context_make(ABTD_ythread_context *p_ctx, - #else - #error "Unknown pointer size." - #endif -+#ifdef ABT_CONFIG_ENABLE_PEEK_CONTEXT -+ p_ctx->is_peeked = ABT_FALSE; -+#endif - } - - static inline void ABTD_ythread_context_jump(ABTD_ythread_context *p_old, - ABTD_ythread_context *p_new, - void *arg) - { -+#ifdef ABT_CONFIG_ENABLE_PEEK_CONTEXT -+ p_old->is_peeked = ABT_FALSE; -+#endif - p_new->p_uctx_arg = arg; - int ret = swapcontext(&p_old->uctx, &p_new->uctx); - /* Fatal. This out-of-stack error is not recoverable. */ - ABTI_ASSERT(ret == 0); -+#ifdef ABT_CONFIG_ENABLE_PEEK_CONTEXT -+ ABTDI_ucontext_check_peeked(p_old); -+#endif - } - - ABTU_noreturn static inline void -@@ -71,6 +114,21 @@ ABTD_ythread_context_take(ABTD_ythread_context *p_old, - ABTU_unreachable(); - } - -+#ifdef ABT_CONFIG_ENABLE_PEEK_CONTEXT -+static inline void ABTD_ythread_context_peek(ABTD_ythread_context *p_ctx, -+ void (*peek_func)(void *), -+ void *arg) -+{ -+ ucontext_t self_uctx; -+ p_ctx->peek_arg = arg; -+ p_ctx->peek_func = peek_func; -+ p_ctx->p_peek_uctx = &self_uctx; -+ p_ctx->is_peeked = ABT_TRUE; -+ int ret = swapcontext(&self_uctx, &p_ctx->uctx); -+ ABTI_ASSERT(ret == 0); -+} -+#endif -+ - #if ABT_CONFIG_THREAD_TYPE == ABT_THREAD_TYPE_DYNAMIC_PROMOTION - #error "ABTD_ythread_context_make_and_call is not implemented." - #endif -diff --git a/src/include/abti.h b/src/include/abti.h -index 803463e..04a0e51 100644 ---- a/src/include/abti.h -+++ b/src/include/abti.h -@@ -113,11 +113,10 @@ typedef struct ABTI_thread_attr ABTI_thread_attr; - typedef struct ABTI_ythread ABTI_ythread; - typedef struct ABTI_thread_mig_data ABTI_thread_mig_data; - typedef uint32_t ABTI_thread_type; --typedef struct ABTI_ythread_htable ABTI_ythread_htable; --typedef struct ABTI_ythread_queue ABTI_ythread_queue; - typedef struct ABTI_key ABTI_key; - typedef struct ABTI_ktelem ABTI_ktelem; - typedef struct ABTI_ktable ABTI_ktable; -+typedef struct ABTI_waitlist ABTI_waitlist; - typedef struct ABTI_mutex_attr ABTI_mutex_attr; - typedef struct ABTI_mutex ABTI_mutex; - typedef struct ABTI_cond ABTI_cond; -@@ -150,20 +149,24 @@ typedef struct ABTI_spinlock ABTI_spinlock; - #include "abti_mem_pool.h" - - /* Definitions */ -+struct ABTI_waitlist { -+ ABTI_thread *p_head; -+ ABTI_thread *p_tail; -+}; -+ - struct ABTI_mutex_attr { - uint32_t attrs; /* bit-or'ed attributes */ - uint32_t nesting_cnt; /* nesting count */ - ABTI_thread_id owner_id; /* owner's ID */ -- uint32_t max_handovers; /* max. # of handovers */ -- uint32_t max_wakeups; /* max. # of wakeups */ - }; - - struct ABTI_mutex { -- ABTD_atomic_uint32 val; /* 0: unlocked, 1: locked */ -- ABTI_mutex_attr attr; /* attributes */ -- ABTI_ythread_htable *p_htable; /* a set of queues */ -- ABTI_ythread *p_handover; /* next ULT for the mutex handover */ -- ABTI_ythread *p_giver; /* current ULT that hands over the mutex */ -+ ABTI_spinlock lock; /* lock */ -+ ABTI_mutex_attr attr; /* attributes */ -+#ifndef ABT_CONFIG_USE_SIMPLE_MUTEX -+ ABTI_spinlock waiter_lock; /* lock */ -+ ABTI_waitlist waitlist; /* waiting list */ -+#endif - }; - - struct ABTI_global { -@@ -178,20 +181,20 @@ struct ABTI_global { - ABT_bool set_affinity; /* Whether CPU affinity is used */ - ABT_bool use_logging; /* Whether logging is used */ - ABT_bool use_debug; /* Whether debug output is used */ -- int key_table_size; /* Default key table size */ -+ uint32_t key_table_size; /* Default key table size */ - size_t thread_stacksize; /* Default stack size for ULT (in bytes) */ - size_t sched_stacksize; /* Default stack size for sched (in bytes) */ - uint32_t sched_event_freq; /* Default check frequency for sched */ -- long sched_sleep_nsec; /* Default nanoseconds for scheduler sleep */ -+ uint64_t sched_sleep_nsec; /* Default nanoseconds for scheduler sleep */ - ABTI_ythread *p_main_ythread; /* ULT of the main function */ - -- uint32_t mutex_max_handovers; /* Default max. # of local handovers */ -- uint32_t mutex_max_wakeups; /* Default max. # of wakeups */ -- uint32_t os_page_size; /* OS page size */ -- uint32_t huge_page_size; /* Huge page size */ -+ uint32_t -+ mutex_max_handovers; /* Default max. # of local handovers (unused) */ -+ uint32_t mutex_max_wakeups; /* Default max. # of wakeups (unused) */ -+ size_t huge_page_size; /* Huge page size */ - #ifdef ABT_CONFIG_USE_MEM_POOL -- uint32_t mem_page_size; /* Page size for memory allocation */ -- uint32_t mem_sp_size; /* Stack page size */ -+ size_t mem_page_size; /* Page size for memory allocation */ -+ size_t mem_sp_size; /* Stack page size */ - uint32_t mem_max_stacks; /* Max. # of stacks kept in each ES */ - uint32_t mem_max_descs; /* Max. # of descriptors kept in each ES */ - int mem_lp_alloc; /* How to allocate large pages */ -@@ -263,7 +266,7 @@ struct ABTI_sched { - ABT_sched_type type; /* Can yield or not (ULT or task) */ - ABTD_atomic_uint32 request; /* Request */ - ABT_pool *pools; /* Thread pools */ -- int num_pools; /* Number of thread pools */ -+ size_t num_pools; /* Number of thread pools */ - ABTI_ythread *p_ythread; /* Associated ULT */ - void *data; /* Data for a specific scheduler */ - -@@ -376,9 +379,7 @@ struct ABTI_ktable { - struct ABTI_cond { - ABTI_spinlock lock; - ABTI_mutex *p_waiter_mutex; -- size_t num_waiters; -- ABTI_thread *p_head; /* Head of waiters */ -- ABTI_thread *p_tail; /* Tail of waiters */ -+ ABTI_waitlist waitlist; - }; - - struct ABTI_rwlock { -@@ -392,32 +393,35 @@ struct ABTI_eventual { - ABTI_spinlock lock; - ABT_bool ready; - void *value; -- int nbytes; -- ABTI_thread *p_head; /* Head of waiters */ -- ABTI_thread *p_tail; /* Tail of waiters */ -+ size_t nbytes; -+ ABTI_waitlist waitlist; - }; - - struct ABTI_future { - ABTI_spinlock lock; -- ABTD_atomic_uint32 counter; -- uint32_t compartments; -+ ABTD_atomic_size counter; -+ size_t compartments; - void **array; - void (*p_callback)(void **arg); -- ABTI_thread *p_head; /* Head of waiters */ -- ABTI_thread *p_tail; /* Tail of waiters */ -+ ABTI_waitlist waitlist; - }; - - struct ABTI_barrier { -- uint32_t num_waiters; -- volatile uint32_t counter; -- ABTI_ythread **waiters; -- ABT_unit_type *waiter_type; -+ size_t num_waiters; -+ volatile size_t counter; - ABTI_spinlock lock; -+ ABTI_waitlist waitlist; - }; - - struct ABTI_xstream_barrier { - uint32_t num_waiters; -+#ifdef HAVE_PTHREAD_BARRIER_INIT - ABTD_xstream_barrier bar; -+#else -+ ABTI_spinlock lock; -+ uint32_t counter; -+ ABTD_atomic_uint64 tag; -+#endif - }; - - struct ABTI_timer { -@@ -546,38 +550,14 @@ ABTU_ret_err int - ABTI_thread_attr_dup(const ABTI_thread_attr *p_attr, - ABTI_thread_attr **pp_dup_attr) ABTU_ret_err; - --/* Thread hash table */ --ABTU_ret_err int ABTI_ythread_htable_create(uint32_t num_rows, -- ABTI_ythread_htable **pp_htable); --void ABTI_ythread_htable_free(ABTI_ythread_htable *p_htable); --void ABTI_ythread_htable_push(ABTI_ythread_htable *p_htable, int idx, -- ABTI_ythread *p_ythread); --void ABTI_ythread_htable_push_low(ABTI_ythread_htable *p_htable, int idx, -- ABTI_ythread *p_ythread); --ABTI_ythread *ABTI_ythread_htable_pop(ABTI_ythread_htable *p_htable, -- ABTI_ythread_queue *p_queue); --ABTI_ythread *ABTI_ythread_htable_pop_low(ABTI_ythread_htable *p_htable, -- ABTI_ythread_queue *p_queue); --ABT_bool ABTI_ythread_htable_switch_low(ABTI_xstream **pp_local_xstream, -- ABTI_ythread_queue *p_queue, -- ABTI_ythread *p_ythread, -- ABTI_ythread_htable *p_htable, -- ABT_sync_event_type sync_event_type, -- void *p_sync); - /* Key */ - void ABTI_ktable_free(ABTI_local *p_local, ABTI_ktable *p_ktable); - --/* Mutex */ --void ABTI_mutex_wait(ABTI_xstream **pp_local_xstream, ABTI_mutex *p_mutex, -- int val); --void ABTI_mutex_wait_low(ABTI_xstream **pp_local_xstream, ABTI_mutex *p_mutex, -- int val); --void ABTI_mutex_wake_de(ABTI_local *p_local, ABTI_mutex *p_mutex); -- - /* Information */ - void ABTI_info_print_config(FILE *fp); - void ABTI_info_check_print_all_thread_stacks(void); - -+#include "abti_timer.h" - #include "abti_log.h" - #include "abti_local.h" - #include "abti_self.h" -@@ -589,6 +569,7 @@ void ABTI_info_check_print_all_thread_stacks(void); - #include "abti_tool.h" - #include "abti_ythread.h" - #include "abti_thread_attr.h" -+#include "abti_waitlist.h" - #include "abti_mutex.h" - #include "abti_mutex_attr.h" - #include "abti_cond.h" -@@ -597,7 +578,6 @@ void ABTI_info_check_print_all_thread_stacks(void); - #include "abti_future.h" - #include "abti_barrier.h" - #include "abti_stream_barrier.h" --#include "abti_timer.h" - #include "abti_mem.h" - #include "abti_key.h" - -diff --git a/src/include/abti_cond.h b/src/include/abti_cond.h -index c34b8fa..eb966ae 100644 ---- a/src/include/abti_cond.h -+++ b/src/include/abti_cond.h -@@ -14,9 +14,7 @@ static inline void ABTI_cond_init(ABTI_cond *p_cond) - { - ABTI_spinlock_clear(&p_cond->lock); - p_cond->p_waiter_mutex = NULL; -- p_cond->num_waiters = 0; -- p_cond->p_head = NULL; -- p_cond->p_tail = NULL; -+ ABTI_waitlist_init(&p_cond->waitlist); - } - - static inline void ABTI_cond_fini(ABTI_cond *p_cond) -@@ -60,24 +58,6 @@ static inline ABT_cond ABTI_cond_get_handle(ABTI_cond *p_cond) - ABTU_ret_err static inline int - ABTI_cond_wait(ABTI_local **pp_local, ABTI_cond *p_cond, ABTI_mutex *p_mutex) - { -- ABTI_ythread *p_ythread = NULL; -- ABTI_thread *p_thread; -- -- ABTI_xstream *p_local_xstream = ABTI_local_get_xstream_or_null(*pp_local); -- if (!ABTI_IS_EXT_THREAD_ENABLED || p_local_xstream) { -- p_thread = p_local_xstream->p_thread; -- p_ythread = ABTI_thread_get_ythread_or_null(p_thread); -- } -- if (!p_ythread) { -- /* external thread or non-yieldable thread */ -- int abt_errno = ABTU_calloc(1, sizeof(ABTI_thread), (void **)&p_thread); -- ABTI_CHECK_ERROR(abt_errno); -- p_thread->type = ABTI_THREAD_TYPE_EXT; -- /* use state for synchronization */ -- ABTD_atomic_relaxed_store_int(&p_thread->state, -- ABT_THREAD_STATE_BLOCKED); -- } -- - ABTI_spinlock_acquire(&p_cond->lock); - - if (p_cond->p_waiter_mutex == NULL) { -@@ -85,52 +65,14 @@ ABTI_cond_wait(ABTI_local **pp_local, ABTI_cond *p_cond, ABTI_mutex *p_mutex) - } else { - if (p_cond->p_waiter_mutex != p_mutex) { - ABTI_spinlock_release(&p_cond->lock); -- if (!p_ythread) -- ABTU_free(p_thread); - return ABT_ERR_INV_MUTEX; - } - } - -- if (p_cond->num_waiters == 0) { -- p_thread->p_prev = p_thread; -- p_thread->p_next = p_thread; -- p_cond->p_head = p_thread; -- p_cond->p_tail = p_thread; -- } else { -- p_cond->p_tail->p_next = p_thread; -- p_cond->p_head->p_prev = p_thread; -- p_thread->p_prev = p_cond->p_tail; -- p_thread->p_next = p_cond->p_head; -- p_cond->p_tail = p_thread; -- } -- -- p_cond->num_waiters++; -- -- if (p_ythread) { -- /* Change the ULT's state to BLOCKED */ -- ABTI_ythread_set_blocked(p_ythread); -- -- ABTI_spinlock_release(&p_cond->lock); -- -- /* Unlock the mutex that the calling ULT is holding */ -- /* FIXME: should check if mutex was locked by the calling ULT */ -- ABTI_mutex_unlock(ABTI_xstream_get_local(p_local_xstream), p_mutex); -- -- /* Suspend the current ULT */ -- ABTI_ythread_suspend(&p_local_xstream, p_ythread, -- ABT_SYNC_EVENT_TYPE_COND, (void *)p_cond); -- *pp_local = ABTI_xstream_get_local(p_local_xstream); -- } else { -- ABTI_spinlock_release(&p_cond->lock); -- ABTI_mutex_unlock(ABTI_xstream_get_local(p_local_xstream), p_mutex); -- -- /* External thread is waiting here. */ -- while (ABTD_atomic_acquire_load_int(&p_thread->state) != -- ABT_THREAD_STATE_READY) -- ; -- ABTU_free(p_thread); -- } -- -+ ABTI_mutex_unlock(*pp_local, p_mutex); -+ ABTI_waitlist_wait_and_unlock(pp_local, &p_cond->waitlist, &p_cond->lock, -+ ABT_FALSE, ABT_SYNC_EVENT_TYPE_COND, -+ (void *)p_cond); - /* Lock the mutex again */ - ABTI_mutex_lock(pp_local, p_mutex); - return ABT_SUCCESS; -@@ -139,43 +81,8 @@ ABTI_cond_wait(ABTI_local **pp_local, ABTI_cond *p_cond, ABTI_mutex *p_mutex) - static inline void ABTI_cond_broadcast(ABTI_local *p_local, ABTI_cond *p_cond) - { - ABTI_spinlock_acquire(&p_cond->lock); -- -- if (p_cond->num_waiters == 0) { -- ABTI_spinlock_release(&p_cond->lock); -- return; -- } -- - /* Wake up all waiting ULTs */ -- ABTI_thread *p_head = p_cond->p_head; -- ABTI_thread *p_thread = p_head; -- while (1) { -- ABTI_thread *p_next = p_thread->p_next; -- -- p_thread->p_prev = NULL; -- p_thread->p_next = NULL; -- -- ABTI_ythread *p_ythread = ABTI_thread_get_ythread_or_null(p_thread); -- if (p_ythread) { -- ABTI_ythread_set_ready(p_local, p_ythread); -- } else { -- /* When the head is an external thread */ -- ABTD_atomic_release_store_int(&p_thread->state, -- ABT_THREAD_STATE_READY); -- } -- -- /* Next ULT */ -- if (p_next != p_head) { -- p_thread = p_next; -- } else { -- break; -- } -- } -- -- p_cond->p_waiter_mutex = NULL; -- p_cond->num_waiters = 0; -- p_cond->p_head = NULL; -- p_cond->p_tail = NULL; -- -+ ABTI_waitlist_broadcast(p_local, &p_cond->waitlist); - ABTI_spinlock_release(&p_cond->lock); - } - -diff --git a/src/include/abti_key.h b/src/include/abti_key.h -index a4b0640..b7254aa 100644 ---- a/src/include/abti_key.h -+++ b/src/include/abti_key.h -@@ -68,15 +68,15 @@ ABTU_ret_err static inline int ABTI_ktable_create(ABTI_local *p_local, - ABTI_ktable **pp_ktable) - { - ABTI_ktable *p_ktable; -- int key_table_size = gp_ABTI_global->key_table_size; -+ uint32_t key_table_size = gp_ABTI_global->key_table_size; - /* size must be a power of 2. */ - ABTI_ASSERT((key_table_size & (key_table_size - 1)) == 0); - /* max alignment must be a power of 2. */ - ABTI_STATIC_ASSERT((ABTU_MAX_ALIGNMENT & (ABTU_MAX_ALIGNMENT - 1)) == 0); - size_t ktable_size = -- (offsetof(ABTI_ktable, p_elems) + -- sizeof(ABTD_atomic_ptr) * key_table_size + ABTU_MAX_ALIGNMENT - 1) & -- (~(ABTU_MAX_ALIGNMENT - 1)); -+ ABTU_roundup_size(offsetof(ABTI_ktable, p_elems) + -+ sizeof(ABTD_atomic_ptr) * key_table_size, -+ ABTU_MAX_ALIGNMENT); - /* Since only one ES can access the memory pool on creation, this uses an - * unsafe memory pool without taking a lock. */ - if (ABTU_likely(ktable_size <= ABTI_KTABLE_DESC_SIZE)) { -diff --git a/src/include/abti_mem.h b/src/include/abti_mem.h -index 47cffee..407cbec 100644 ---- a/src/include/abti_mem.h -+++ b/src/include/abti_mem.h -@@ -12,8 +12,7 @@ - * used to determine whether the descriptor is allocated externally (i.e., - * malloc()) or taken from a memory pool. */ - #define ABTI_MEM_POOL_DESC_ELEM_SIZE \ -- ((sizeof(ABTI_thread) + ABT_CONFIG_STATIC_CACHELINE_SIZE - 1) & \ -- (~(ABT_CONFIG_STATIC_CACHELINE_SIZE - 1))) -+ ABTU_roundup_size(sizeof(ABTI_thread), ABT_CONFIG_STATIC_CACHELINE_SIZE) - - enum { - ABTI_MEM_LP_MALLOC = 0, -@@ -119,8 +118,7 @@ ABTU_ret_err static inline int ABTI_mem_alloc_ythread_malloc_desc_stack_impl( - { - /* stacksize must be a multiple of ABT_CONFIG_STATIC_CACHELINE_SIZE. */ - size_t alloc_stacksize = -- (stacksize + ABT_CONFIG_STATIC_CACHELINE_SIZE - 1) & -- (~(ABT_CONFIG_STATIC_CACHELINE_SIZE - 1)); -+ ABTU_roundup_size(stacksize, ABT_CONFIG_STATIC_CACHELINE_SIZE); - char *p_stack; - int abt_errno = - ABTU_malloc(alloc_stacksize + sizeof(ABTI_ythread), (void **)&p_stack); -diff --git a/src/include/abti_mem_pool.h b/src/include/abti_mem_pool.h -index b094a2a..2264731 100644 ---- a/src/include/abti_mem_pool.h -+++ b/src/include/abti_mem_pool.h -@@ -14,7 +14,7 @@ typedef union ABTI_mem_pool_header_bucket_info { - /* This is used when it is in ABTI_mem_pool_global_pool */ - ABTI_sync_lifo_element lifo_elem; - /* This is used when it is in ABTI_mem_pool_local_pool */ -- int num_headers; -+ size_t num_headers; - } ABTI_mem_pool_header_bucket_info; - - typedef struct ABTI_mem_pool_header { -@@ -47,15 +47,16 @@ typedef struct ABTI_mem_pool_page { - * . - */ - typedef struct ABTI_mem_pool_global_pool { -- size_t header_size; /* Size of header */ -- size_t page_size; /* Size of page (mem of ABTI_mem_pool_page) */ -- size_t alignment_hint; /* Alignment hint for page */ -- size_t header_offset; /* Offset of ABTI_mem_pool_header from the top -- * of the memory segment; i.e., the pool returns -- * p_header_memory_top + offset. */ -- int num_headers_per_bucket; /* Number of headers per bucket. */ -- int num_lp_type_requests; /* Number of requests for large page allocation. -- */ -+ size_t header_size; /* Size of header */ -+ size_t page_size; /* Size of page (mem of ABTI_mem_pool_page) */ -+ size_t alignment_hint; /* Alignment hint for page */ -+ size_t header_offset; /* Offset of ABTI_mem_pool_header from the top -+ * of the memory segment; i.e., the pool returns -+ * p_header_memory_top + offset. */ -+ size_t num_headers_per_bucket; /* Number of headers per bucket. */ -+ uint32_t -+ num_lp_type_requests; /* Number of requests for large page allocation. -+ */ - ABTU_MEM_LARGEPAGE_TYPE - lp_type_requests[4]; /* Requests for large page allocation */ - ABTU_align_member_var(ABT_CONFIG_STATIC_CACHELINE_SIZE) -@@ -96,10 +97,10 @@ typedef struct ABTI_mem_pool_local_pool { - } ABTI_mem_pool_local_pool; - - void ABTI_mem_pool_init_global_pool( -- ABTI_mem_pool_global_pool *p_global_pool, int num_headers_per_bucket, -+ ABTI_mem_pool_global_pool *p_global_pool, size_t num_headers_per_bucket, - size_t header_size, size_t header_offset, size_t page_size, -- const ABTU_MEM_LARGEPAGE_TYPE *lp_type_requests, int num_lp_type_requests, -- size_t alignment_hint); -+ const ABTU_MEM_LARGEPAGE_TYPE *lp_type_requests, -+ uint32_t num_lp_type_requests, size_t alignment_hint); - void ABTI_mem_pool_destroy_global_pool( - ABTI_mem_pool_global_pool *p_global_pool); - void ABTI_mem_pool_init_local_pool(ABTI_mem_pool_local_pool *p_local_pool, -@@ -115,7 +116,7 @@ ABTI_mem_pool_alloc(ABTI_mem_pool_local_pool *p_local_pool, void **p_mem) - { - size_t bucket_index = p_local_pool->bucket_index; - ABTI_mem_pool_header *cur_bucket = p_local_pool->buckets[bucket_index]; -- int num_headers_in_cur_bucket = cur_bucket->bucket_info.num_headers; -+ size_t num_headers_in_cur_bucket = cur_bucket->bucket_info.num_headers; - /* At least one header is available in the current bucket, so it must be - * larger than 0. */ - ABTI_ASSERT(num_headers_in_cur_bucket >= 1); -@@ -124,14 +125,14 @@ ABTI_mem_pool_alloc(ABTI_mem_pool_local_pool *p_local_pool, void **p_mem) - if (bucket_index == 0) { - /* cur_bucket is the last header in this pool. - * Let's get some buckets from the global pool. */ -- int i; -+ size_t i; - for (i = 0; i < ABT_MEM_POOL_NUM_TAKE_BUCKETS; i++) { - int abt_errno = - ABTI_mem_pool_take_bucket(p_local_pool->p_global_pool, - &p_local_pool->buckets[i]); - if (ABTI_IS_ERROR_CHECK_ENABLED && abt_errno != ABT_SUCCESS) { - /* Return buckets that have been already taken. */ -- int j; -+ size_t j; - for (j = 0; j < i; j++) { - ABTI_mem_pool_return_bucket(p_local_pool->p_global_pool, - p_local_pool->buckets[j]); -@@ -166,7 +167,7 @@ static inline void ABTI_mem_pool_free(ABTI_mem_pool_local_pool *p_local_pool, - p_local_pool->num_headers_per_bucket) { - /* cur_bucket is full. */ - if (++bucket_index == ABT_MEM_POOL_MAX_LOCAL_BUCKETS) { -- int i; -+ size_t i; - /* All buckets are full, so let's return some old buckets. */ - for (i = 0; i < ABT_MEM_POOL_NUM_RETURN_BUCKETS; i++) { - ABTI_mem_pool_return_bucket(p_local_pool->p_global_pool, -diff --git a/src/include/abti_mutex.h b/src/include/abti_mutex.h -index 2998577..84b2505 100644 ---- a/src/include/abti_mutex.h -+++ b/src/include/abti_mutex.h -@@ -36,125 +36,162 @@ static inline ABT_mutex ABTI_mutex_get_handle(ABTI_mutex *p_mutex) - #endif - } - --ABTU_ret_err static inline int ABTI_mutex_init(ABTI_mutex *p_mutex) -+static inline void ABTI_mutex_init(ABTI_mutex *p_mutex) - { -- ABTD_atomic_relaxed_store_uint32(&p_mutex->val, 0); -- p_mutex->attr.attrs = ABTI_MUTEX_ATTR_NONE; -- p_mutex->attr.max_handovers = gp_ABTI_global->mutex_max_handovers; -- p_mutex->attr.max_wakeups = gp_ABTI_global->mutex_max_wakeups; -+ ABTI_spinlock_clear(&p_mutex->lock); - #ifndef ABT_CONFIG_USE_SIMPLE_MUTEX -- int abt_errno = ABTI_ythread_htable_create(gp_ABTI_global->max_xstreams, -- &p_mutex->p_htable); -- ABTI_CHECK_ERROR(abt_errno); -- p_mutex->p_handover = NULL; -- p_mutex->p_giver = NULL; -+ ABTI_spinlock_clear(&p_mutex->waiter_lock); -+ ABTI_waitlist_init(&p_mutex->waitlist); - #endif -- return ABT_SUCCESS; -+ p_mutex->attr.attrs = ABTI_MUTEX_ATTR_NONE; -+ p_mutex->attr.nesting_cnt = 0; -+ p_mutex->attr.owner_id = 0; - } - --#ifdef ABT_CONFIG_USE_SIMPLE_MUTEX --#define ABTI_mutex_fini(p_mutex) --#else - static inline void ABTI_mutex_fini(ABTI_mutex *p_mutex) - { -- ABTI_ythread_htable_free(p_mutex->p_htable); --} -+#ifndef ABT_CONFIG_USE_SIMPLE_MUTEX -+ ABTI_spinlock_acquire(&p_mutex->waiter_lock); - #endif -+} - --static inline void ABTI_mutex_spinlock(ABTI_mutex *p_mutex) -+static inline void ABTI_mutex_lock_no_recursion(ABTI_local **pp_local, -+ ABTI_mutex *p_mutex) - { -- /* ABTI_spinlock_ functions cannot be used since p_mutex->val can take -- * other values (i.e., not UNLOCKED nor LOCKED.) */ -- while (!ABTD_atomic_bool_cas_weak_uint32(&p_mutex->val, 0, 1)) { -- while (ABTD_atomic_acquire_load_uint32(&p_mutex->val) != 0) -- ; -+#ifndef ABT_CONFIG_USE_SIMPLE_MUTEX -+ while (ABTI_spinlock_try_acquire(&p_mutex->lock)) { -+ /* Failed to take a lock, so let's add it to the waiter list. */ -+ ABTI_spinlock_acquire(&p_mutex->waiter_lock); -+ /* Maybe the mutex lock has been already released. Check it. */ -+ if (!ABTI_spinlock_try_acquire(&p_mutex->lock)) { -+ /* Lock has been taken. */ -+ ABTI_spinlock_release(&p_mutex->waiter_lock); -+ break; -+ } -+ /* Wait on waitlist. */ -+ ABTI_waitlist_wait_and_unlock(pp_local, &p_mutex->waitlist, -+ &p_mutex->waiter_lock, ABT_FALSE, -+ ABT_SYNC_EVENT_TYPE_MUTEX, -+ (void *)p_mutex); - } -- LOG_DEBUG("%p: spinlock\n", p_mutex); -+ /* Take a lock. */ -+#else -+ /* Simple yield-based implementation */ -+ ABTI_ythread *p_ythread = NULL; -+ ABTI_xstream *p_local_xstream = ABTI_local_get_xstream_or_null(*pp_local); -+ if (!ABTI_IS_EXT_THREAD_ENABLED || p_local_xstream) -+ p_ythread = ABTI_thread_get_ythread_or_null(p_local_xstream->p_thread); -+ -+ if (p_ythread) { -+ while (ABTI_spinlock_try_acquire(&p_mutex->lock)) { -+ ABTI_ythread_yield(&p_local_xstream, p_ythread, -+ ABT_SYNC_EVENT_TYPE_MUTEX, (void *)p_mutex); -+ *pp_local = ABTI_xstream_get_local(p_local_xstream); -+ } -+ } else { -+ /* Use spinlock. */ -+ ABTI_spinlock_acquire(&p_mutex->lock); -+ } -+#endif - } - - static inline void ABTI_mutex_lock(ABTI_local **pp_local, ABTI_mutex *p_mutex) - { -- ABTI_xstream *p_local_xstream = ABTI_local_get_xstream_or_null(*pp_local); -- if (ABTI_IS_EXT_THREAD_ENABLED && !p_local_xstream) { -- ABTI_mutex_spinlock(p_mutex); -- return; -- } -- ABTI_ythread *p_ythread = -- ABTI_thread_get_ythread_or_null(p_local_xstream->p_thread); -- if (!p_ythread) { -- ABTI_mutex_spinlock(p_mutex); -- return; -- } --#ifdef ABT_CONFIG_USE_SIMPLE_MUTEX -- LOG_DEBUG("%p: lock - try\n", p_mutex); -- while (!ABTD_atomic_bool_cas_strong_uint32(&p_mutex->val, 0, 1)) { -- ABTI_ythread_yield(&p_local_xstream, p_ythread, -- ABT_SYNC_EVENT_TYPE_MUTEX, (void *)p_mutex); -- *pp_local = ABTI_xstream_get_local(p_local_xstream); -- } -- LOG_DEBUG("%p: lock - acquired\n", p_mutex); --#else -- /* Only ULTs can yield when the mutex has been locked. For others, -- * just call mutex_spinlock. */ -- LOG_DEBUG("%p: lock - try\n", p_mutex); -- int c; -- if ((c = ABTD_atomic_val_cas_strong_uint32(&p_mutex->val, 0, 1)) != 0) { -- if (c != 2) { -- c = ABTD_atomic_exchange_uint32(&p_mutex->val, 2); -+ if (p_mutex->attr.attrs & ABTI_MUTEX_ATTR_RECURSIVE) { -+ /* Recursive mutex */ -+ ABTI_thread_id self_id = ABTI_self_get_thread_id(*pp_local); -+ if (self_id != p_mutex->attr.owner_id) { -+ ABTI_mutex_lock_no_recursion(pp_local, p_mutex); -+ ABTI_ASSERT(p_mutex->attr.nesting_cnt == 0); -+ p_mutex->attr.owner_id = self_id; -+ } else { -+ /* Increment a nesting count. */ -+ p_mutex->attr.nesting_cnt++; - } -- while (c != 0) { -- ABTI_mutex_wait(&p_local_xstream, p_mutex, 2); -- *pp_local = ABTI_xstream_get_local(p_local_xstream); -+ } else { -+ ABTI_mutex_lock_no_recursion(pp_local, p_mutex); -+ } -+} - -- /* If the mutex has been handed over to the current ULT from -- * other ULT on the same ES, we don't need to change the mutex -- * state. */ -- if (p_mutex->p_handover) { -- if (p_ythread == p_mutex->p_handover) { -- p_mutex->p_handover = NULL; -- ABTD_atomic_release_store_uint32(&p_mutex->val, 2); -+static inline int ABTI_mutex_trylock_no_recursion(ABTI_mutex *p_mutex) -+{ -+ return ABTI_spinlock_try_acquire(&p_mutex->lock) ? ABT_ERR_MUTEX_LOCKED -+ : ABT_SUCCESS; -+} - -- /* Push the previous ULT to its pool */ -- ABTI_ythread *p_giver = p_mutex->p_giver; -- ABTD_atomic_release_store_int(&p_giver->thread.state, -- ABT_THREAD_STATE_READY); -- ABTI_pool_push(p_giver->thread.p_pool, -- p_giver->thread.unit); -- break; -- } -+static inline int ABTI_mutex_trylock(ABTI_local *p_local, ABTI_mutex *p_mutex) -+{ -+ if (p_mutex->attr.attrs & ABTI_MUTEX_ATTR_RECURSIVE) { -+ /* Recursive mutex */ -+ ABTI_thread_id self_id = ABTI_self_get_thread_id(p_local); -+ if (self_id != p_mutex->attr.owner_id) { -+ int abt_errno = ABTI_mutex_trylock_no_recursion(p_mutex); -+ if (abt_errno == ABT_SUCCESS) { -+ ABTI_ASSERT(p_mutex->attr.nesting_cnt == 0); -+ p_mutex->attr.owner_id = self_id; - } -- -- c = ABTD_atomic_exchange_uint32(&p_mutex->val, 2); -+ return abt_errno; -+ } else { -+ /* Increment a nesting count. */ -+ p_mutex->attr.nesting_cnt++; -+ return ABT_SUCCESS; - } -+ } else { -+ return ABTI_mutex_trylock_no_recursion(p_mutex); - } -- LOG_DEBUG("%p: lock - acquired\n", p_mutex); -- return; --#endif - } - --static inline int ABTI_mutex_trylock(ABTI_mutex *p_mutex) -+static inline void ABTI_mutex_spinlock_no_recursion(ABTI_mutex *p_mutex) -+{ -+ ABTI_spinlock_acquire(&p_mutex->lock); -+} -+ -+static inline void ABTI_mutex_spinlock(ABTI_local *p_local, ABTI_mutex *p_mutex) - { -- if (!ABTD_atomic_bool_cas_strong_uint32(&p_mutex->val, 0, 1)) { -- return ABT_ERR_MUTEX_LOCKED; -+ if (p_mutex->attr.attrs & ABTI_MUTEX_ATTR_RECURSIVE) { -+ /* Recursive mutex */ -+ ABTI_thread_id self_id = ABTI_self_get_thread_id(p_local); -+ if (self_id != p_mutex->attr.owner_id) { -+ ABTI_mutex_spinlock_no_recursion(p_mutex); -+ ABTI_ASSERT(p_mutex->attr.nesting_cnt == 0); -+ p_mutex->attr.owner_id = self_id; -+ } else { -+ /* Increment a nesting count. */ -+ p_mutex->attr.nesting_cnt++; -+ } -+ } else { -+ ABTI_mutex_spinlock_no_recursion(p_mutex); - } -- return ABT_SUCCESS; - } - --static inline void ABTI_mutex_unlock(ABTI_local *p_local, ABTI_mutex *p_mutex) -+static inline void ABTI_mutex_unlock_no_recursion(ABTI_local *p_local, -+ ABTI_mutex *p_mutex) - { --#ifdef ABT_CONFIG_USE_SIMPLE_MUTEX -- ABTD_atomic_mem_barrier(); -- ABTD_atomic_release_store_uint32(&p_mutex->val, 0); -- LOG_DEBUG("%p: unlock w/o wake\n", p_mutex); -+#ifndef ABT_CONFIG_USE_SIMPLE_MUTEX -+ ABTI_spinlock_acquire(&p_mutex->waiter_lock); -+ ABTI_spinlock_release(&p_mutex->lock); -+ /* Operations of waitlist must be done while taking waiter_lock. */ -+ ABTI_waitlist_broadcast(p_local, &p_mutex->waitlist); -+ ABTI_spinlock_release(&p_mutex->waiter_lock); - #else -- if (ABTD_atomic_fetch_sub_uint32(&p_mutex->val, 1) != 1) { -- ABTD_atomic_release_store_uint32(&p_mutex->val, 0); -- LOG_DEBUG("%p: unlock with wake\n", p_mutex); -- ABTI_mutex_wake_de(p_local, p_mutex); -+ ABTI_spinlock_release(&p_mutex->lock); -+#endif -+} -+ -+static inline void ABTI_mutex_unlock(ABTI_local *p_local, ABTI_mutex *p_mutex) -+{ -+ if (p_mutex->attr.attrs & ABTI_MUTEX_ATTR_RECURSIVE) { -+ /* recursive mutex */ -+ if (p_mutex->attr.nesting_cnt == 0) { -+ p_mutex->attr.owner_id = 0; -+ ABTI_mutex_unlock_no_recursion(p_local, p_mutex); -+ } else { -+ p_mutex->attr.nesting_cnt--; -+ } - } else { -- LOG_DEBUG("%p: unlock w/o wake\n", p_mutex); -+ /* unknown attributes */ -+ ABTI_mutex_unlock_no_recursion(p_local, p_mutex); - } --#endif - } - - #endif /* ABTI_MUTEX_H_INCLUDED */ -diff --git a/src/include/abti_spinlock.h b/src/include/abti_spinlock.h -index eb2ba9e..a7d59a3 100644 ---- a/src/include/abti_spinlock.h -+++ b/src/include/abti_spinlock.h -@@ -15,6 +15,11 @@ struct ABTI_spinlock { - ABTD_ATOMIC_BOOL_STATIC_INITIALIZER(0) \ - } - -+static inline ABT_bool ABTI_spinlock_is_locked(const ABTI_spinlock *p_lock) -+{ -+ return ABTD_atomic_acquire_load_bool(&p_lock->val); -+} -+ - static inline void ABTI_spinlock_clear(ABTI_spinlock *p_lock) - { - ABTD_atomic_relaxed_clear_bool(&p_lock->val); -@@ -23,11 +28,17 @@ static inline void ABTI_spinlock_clear(ABTI_spinlock *p_lock) - static inline void ABTI_spinlock_acquire(ABTI_spinlock *p_lock) - { - while (ABTD_atomic_test_and_set_bool(&p_lock->val)) { -- while (ABTD_atomic_acquire_load_bool(&p_lock->val) != ABT_FALSE) -+ while (ABTI_spinlock_is_locked(p_lock) != ABT_FALSE) - ; - } - } - -+/* Return ABT_FALSE if the lock is acquired. */ -+static inline ABT_bool ABTI_spinlock_try_acquire(ABTI_spinlock *p_lock) -+{ -+ return ABTD_atomic_test_and_set_bool(&p_lock->val) ? ABT_TRUE : ABT_FALSE; -+} -+ - static inline void ABTI_spinlock_release(ABTI_spinlock *p_lock) - { - ABTD_atomic_release_clear_bool(&p_lock->val); -diff --git a/src/include/abti_stream_barrier.h b/src/include/abti_stream_barrier.h -index 510786f..c792e59 100644 ---- a/src/include/abti_stream_barrier.h -+++ b/src/include/abti_stream_barrier.h -@@ -6,7 +6,6 @@ - #ifndef ABTI_XSTREAM_BARRIER_H_INCLUDED - #define ABTI_XSTREAM_BARRIER_H_INCLUDED - --#ifdef HAVE_PTHREAD_BARRIER_INIT - static inline ABTI_xstream_barrier * - ABTI_xstream_barrier_get_ptr(ABT_xstream_barrier barrier) - { -@@ -38,6 +37,5 @@ ABTI_xstream_barrier_get_handle(ABTI_xstream_barrier *p_barrier) - return (ABT_xstream_barrier)p_barrier; - #endif - } --#endif - - #endif /* ABTI_XSTREAM_BARRIER_H_INCLUDED */ -diff --git a/src/include/abti_waitlist.h b/src/include/abti_waitlist.h -new file mode 100644 -index 0000000..d3344ab ---- /dev/null -+++ b/src/include/abti_waitlist.h -@@ -0,0 +1,214 @@ -+/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */ -+/* -+ * See COPYRIGHT in top-level directory. -+ */ -+ -+#ifndef ABTI_WAITLIST_H_INCLUDED -+#define ABTI_WAITLIST_H_INCLUDED -+ -+#include "abt_config.h" -+ -+static inline void ABTI_waitlist_init(ABTI_waitlist *p_waitlist) -+{ -+ p_waitlist->p_head = NULL; -+ p_waitlist->p_tail = NULL; -+} -+ -+static inline void -+ABTI_waitlist_wait_and_unlock(ABTI_local **pp_local, ABTI_waitlist *p_waitlist, -+ ABTI_spinlock *p_lock, ABT_bool blocking, -+ ABT_sync_event_type sync_event_type, void *p_sync) -+{ -+ ABTI_ASSERT(ABTI_spinlock_is_locked(p_lock) == ABT_TRUE); -+ ABTI_ythread *p_ythread = NULL; -+ ABTI_xstream *p_local_xstream = ABTI_local_get_xstream_or_null(*pp_local); -+ if (!ABTI_IS_EXT_THREAD_ENABLED || p_local_xstream) { -+ p_ythread = ABTI_thread_get_ythread_or_null(p_local_xstream->p_thread); -+ } -+ if (!p_ythread || blocking) { -+ /* External thread, non-yieldable thread, or asked to block */ -+ ABTI_thread thread; -+ thread.type = ABTI_THREAD_TYPE_EXT; -+ /* use state for synchronization */ -+ ABTD_atomic_relaxed_store_int(&thread.state, ABT_THREAD_STATE_BLOCKED); -+ /* Add thread to the list. */ -+ thread.p_next = NULL; -+ if (p_waitlist->p_head == NULL) { -+ p_waitlist->p_head = &thread; -+ } else { -+ p_waitlist->p_tail->p_next = &thread; -+ } -+ p_waitlist->p_tail = &thread; -+ -+ /* Non-yieldable thread is waiting here. */ -+ ABTI_spinlock_release(p_lock); -+ while (ABTD_atomic_acquire_load_int(&thread.state) != -+ ABT_THREAD_STATE_READY) -+ ; -+ } else { -+ /* Add p_thread to the list. */ -+ p_ythread->thread.p_next = NULL; -+ if (p_waitlist->p_head == NULL) { -+ p_waitlist->p_head = &p_ythread->thread; -+ } else { -+ p_waitlist->p_tail->p_next = &p_ythread->thread; -+ } -+ p_waitlist->p_tail = &p_ythread->thread; -+ -+ /* Suspend the current ULT */ -+ ABTI_ythread_set_blocked(p_ythread); -+ ABTI_spinlock_release(p_lock); -+ ABTI_ythread_suspend(&p_local_xstream, p_ythread, -+ ABT_SYNC_EVENT_TYPE_EVENTUAL, p_sync); -+ /* Resumed. */ -+ *pp_local = ABTI_xstream_get_local(p_local_xstream); -+ } -+} -+ -+/* Return ABT_TRUE if timed out. */ -+static inline ABT_bool ABTI_waitlist_wait_timedout_and_unlock( -+ ABTI_local **pp_local, ABTI_waitlist *p_waitlist, ABTI_spinlock *p_lock, -+ ABT_bool blocking, double target_time, ABT_sync_event_type sync_event_type, -+ void *p_sync) -+{ -+ ABTI_ASSERT(ABTI_spinlock_is_locked(p_lock) == ABT_TRUE); -+ ABTI_ythread *p_ythread = NULL; -+ ABTI_xstream *p_local_xstream = ABTI_local_get_xstream_or_null(*pp_local); -+ if (!ABTI_IS_EXT_THREAD_ENABLED || p_local_xstream) -+ p_ythread = ABTI_thread_get_ythread_or_null(p_local_xstream->p_thread); -+ -+ /* Always use a dummy thread. */ -+ ABTI_thread thread; -+ thread.type = ABTI_THREAD_TYPE_EXT; -+ /* use state for synchronization */ -+ ABTD_atomic_relaxed_store_int(&thread.state, ABT_THREAD_STATE_BLOCKED); -+ -+ /* Add p_thread to the list. This implementation is tricky since this -+ * updates p_prev as well for removal on timeout while the other functions -+ * (e.g., wait, broadcast, signal) do not update it. */ -+ thread.p_next = NULL; -+ if (p_waitlist->p_head == NULL) { -+ p_waitlist->p_head = &thread; -+ thread.p_prev = NULL; -+ } else { -+ p_waitlist->p_tail->p_next = &thread; -+ thread.p_prev = p_waitlist->p_tail; -+ } -+ p_waitlist->p_tail = &thread; -+ -+ /* Waiting here. */ -+ ABTI_spinlock_release(p_lock); -+ while (ABTD_atomic_acquire_load_int(&thread.state) != -+ ABT_THREAD_STATE_READY) { -+ double cur_time = ABTI_get_wtime(); -+ if (cur_time >= target_time) { -+ /* Timeout. Remove this thread if not signaled even after taking -+ * a lock. */ -+ ABTI_spinlock_acquire(p_lock); -+ ABT_bool is_timedout = -+ (ABTD_atomic_acquire_load_int(&thread.state) != -+ ABT_THREAD_STATE_READY) -+ ? ABT_TRUE -+ : ABT_FALSE; -+ if (is_timedout) { -+ /* This thread is still in the list. */ -+ if (p_waitlist->p_head == &thread) { -+ /* thread is a head. */ -+ /* Note that thread->p_prev cannot be used to check whether -+ * thread is a head or not because signal and broadcast do -+ * not modify thread->p_prev. */ -+ p_waitlist->p_head = thread.p_next; -+ if (!thread.p_next) { -+ /* This thread is p_tail */ -+ ABTI_ASSERT(p_waitlist->p_tail == &thread); -+ p_waitlist->p_tail = NULL; -+ } -+ } else { -+ /* thread is not a head and thus p_prev exists. */ -+ ABTI_ASSERT(thread.p_prev); -+ thread.p_prev->p_next = thread.p_next; -+ if (thread.p_next && thread.type == ABTI_THREAD_TYPE_EXT) { -+ /* Only an external thread (created by this function) -+ * checks p_prev. Note that an external thread is -+ * dummy, so updating p_prev is allowed. */ -+ thread.p_next->p_prev = thread.p_prev; -+ } else { -+ /* This thread is p_tail */ -+ ABTI_ASSERT(p_waitlist->p_tail == &thread); -+ p_waitlist->p_tail = thread.p_prev; -+ } -+ } -+ /* We do not need to modify thread->p_prev and p_next since this -+ * dummy thread is no longer used. */ -+ } -+ ABTI_spinlock_release(p_lock); -+ return is_timedout; -+ } -+ if (p_ythread && !blocking) { -+ ABTI_ythread_yield(&p_local_xstream, p_ythread, sync_event_type, -+ p_sync); -+ *pp_local = ABTI_xstream_get_local(p_local_xstream); -+ } else { -+ ABTD_atomic_pause(); -+ } -+ } -+ /* Singled */ -+ return ABT_FALSE; -+} -+ -+static inline void ABTI_waitlist_signal(ABTI_local *p_local, -+ ABTI_waitlist *p_waitlist) -+{ -+ ABTI_thread *p_thread = p_waitlist->p_head; -+ if (p_thread) { -+ ABTI_thread *p_next = p_thread->p_next; -+ p_thread->p_next = NULL; -+ -+ ABTI_ythread *p_ythread = ABTI_thread_get_ythread_or_null(p_thread); -+ if (p_ythread) { -+ ABTI_ythread_set_ready(p_local, p_ythread); -+ } else { -+ /* When p_thread is an external thread or a tasklet */ -+ ABTD_atomic_release_store_int(&p_thread->state, -+ ABT_THREAD_STATE_READY); -+ } -+ /* After updating p_thread->state, p_thread can be updated and -+ * freed. */ -+ p_waitlist->p_head = p_next; -+ if (!p_next) -+ p_waitlist->p_tail = NULL; -+ } -+} -+ -+static inline void ABTI_waitlist_broadcast(ABTI_local *p_local, -+ ABTI_waitlist *p_waitlist) -+{ -+ ABTI_thread *p_thread = p_waitlist->p_head; -+ if (p_thread) { -+ do { -+ ABTI_thread *p_next = p_thread->p_next; -+ p_thread->p_next = NULL; -+ -+ ABTI_ythread *p_ythread = ABTI_thread_get_ythread_or_null(p_thread); -+ if (p_ythread) { -+ ABTI_ythread_set_ready(p_local, p_ythread); -+ } else { -+ /* When p_thread is an external thread or a tasklet */ -+ ABTD_atomic_release_store_int(&p_thread->state, -+ ABT_THREAD_STATE_READY); -+ } -+ /* After updating p_thread->state, p_thread can be updated and -+ * freed. */ -+ p_thread = p_next; -+ } while (p_thread); -+ p_waitlist->p_head = NULL; -+ p_waitlist->p_tail = NULL; -+ } -+} -+ -+static inline ABT_bool ABTI_waitlist_is_empty(ABTI_waitlist *p_waitlist) -+{ -+ return p_waitlist->p_head ? ABT_TRUE : ABT_FALSE; -+} -+ -+#endif /* ABTI_WAITLIST_H_INCLUDED */ -diff --git a/src/include/abti_ythread.h b/src/include/abti_ythread.h -index d366992..a0b32cd 100644 ---- a/src/include/abti_ythread.h -+++ b/src/include/abti_ythread.h -@@ -299,6 +299,21 @@ static inline ABTI_ythread *ABTI_ythread_context_switch_to_child_internal( - } - } - -+#ifdef ABT_CONFIG_ENABLE_PEEK_CONTEXT -+static inline void ABTI_ythread_context_peek(ABTI_ythread *p_ythread, -+ void (*peek_func)(void *), -+ void *arg) -+{ -+#if ABT_CONFIG_THREAD_TYPE == ABT_THREAD_TYPE_DYNAMIC_PROMOTION -+ if (!ABTI_ythread_is_dynamic_promoted(p_ythread)) { -+ ABTD_ythread_context_arm_ythread(p_ythread->stacksize, -+ p_ythread->p_stack, &p_ythread->ctx); -+ } -+#endif -+ ABTD_ythread_context_peek(&p_ythread->ctx, peek_func, arg); -+} -+#endif -+ - /* Return the previous thread. */ - static inline ABTI_ythread * - ABTI_ythread_context_switch_to_sibling(ABTI_xstream **pp_local_xstream, -diff --git a/src/include/abti_ythread_htable.h b/src/include/abti_ythread_htable.h -deleted file mode 100644 -index fbefbd0..0000000 ---- a/src/include/abti_ythread_htable.h -+++ /dev/null -@@ -1,177 +0,0 @@ --/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */ --/* -- * See COPYRIGHT in top-level directory. -- */ -- --#ifndef ABTI_YTHREAD_HTABLE_H_INCLUDED --#define ABTI_YTHREAD_HTABLE_H_INCLUDED -- --#include "abt_config.h" -- --#if defined(HAVE_LH_LOCK_H) --#include --#elif defined(HAVE_CLH_H) --#include --#else --#define USE_PTHREAD_MUTEX --#endif -- --struct ABTI_ythread_queue { -- ABTD_atomic_uint32 mutex; /* can be initialized by just assigning 0*/ -- uint32_t num_handovers; -- uint32_t num_threads; -- uint32_t pad0; -- ABTI_ythread *head; -- ABTI_ythread *tail; -- char pad1[64 - sizeof(ABTD_atomic_uint32) - sizeof(uint32_t) * 3 - -- sizeof(ABTI_ythread *) * 2]; -- -- /* low priority queue */ -- ABTD_atomic_uint32 low_mutex; /* can be initialized by just assigning 0*/ -- uint32_t low_num_threads; -- ABTI_ythread *low_head; -- ABTI_ythread *low_tail; -- char pad2[64 - sizeof(ABTD_atomic_uint32) - sizeof(uint32_t) - -- sizeof(ABTI_ythread *) * 2]; -- -- /* two doubly-linked lists */ -- ABTI_ythread_queue *p_h_next; -- ABTI_ythread_queue *p_h_prev; -- ABTI_ythread_queue *p_l_next; -- ABTI_ythread_queue *p_l_prev; -- char pad3[64 - sizeof(ABTI_ythread_queue *) * 4]; --}; -- --struct ABTI_ythread_htable { --#if defined(HAVE_LH_LOCK_H) -- lh_lock_t mutex; --#elif defined(HAVE_CLH_H) -- clh_lock_t mutex; --#elif defined(USE_PTHREAD_MUTEX) -- pthread_mutex_t mutex; --#else -- ABTI_spinlock mutex; /* To protect table */ --#endif -- ABTD_atomic_uint32 num_elems; -- uint32_t num_rows; -- ABTI_ythread_queue *queue; -- -- ABTI_ythread_queue *h_list; /* list of non-empty high prio. queues */ -- ABTI_ythread_queue *l_list; /* list of non-empty low prio. queues */ --}; -- --#if defined(HAVE_LH_LOCK_H) --#define ABTI_THREAD_HTABLE_LOCK(m) lh_acquire_lock(&m) --#define ABTI_THREAD_HTABLE_UNLOCK(m) lh_release_lock(&m) --#elif defined(HAVE_CLH_H) --#define ABTI_THREAD_HTABLE_LOCK(m) clh_acquire(&m) --#define ABTI_THREAD_HTABLE_UNLOCK(m) clh_release(&m) --#elif defined(USE_PTHREAD_MUTEX) --#define ABTI_THREAD_HTABLE_LOCK(m) pthread_mutex_lock(&m) --#define ABTI_THREAD_HTABLE_UNLOCK(m) pthread_mutex_unlock(&m) --#else --#define ABTI_THREAD_HTABLE_LOCK(m) ABTI_spinlock_acquire(&m) --#define ABTI_THREAD_HTABLE_UNLOCK(m) ABTI_spinlock_release(&m) --#endif -- --static inline void ABTI_ythread_queue_acquire_mutex(ABTI_ythread_queue *p_queue) --{ -- while (!ABTD_atomic_bool_cas_weak_uint32(&p_queue->mutex, 0, 1)) { -- while (ABTD_atomic_acquire_load_uint32(&p_queue->mutex) != 0) -- ; -- } --} -- --static inline void ABTI_ythread_queue_release_mutex(ABTI_ythread_queue *p_queue) --{ -- ABTD_atomic_release_store_uint32(&p_queue->mutex, 0); --} -- --static inline void --ABTI_ythread_queue_acquire_low_mutex(ABTI_ythread_queue *p_queue) --{ -- while (!ABTD_atomic_bool_cas_weak_uint32(&p_queue->low_mutex, 0, 1)) { -- while (ABTD_atomic_acquire_load_uint32(&p_queue->low_mutex) != 0) -- ; -- } --} -- --static inline void --ABTI_ythread_queue_release_low_mutex(ABTI_ythread_queue *p_queue) --{ -- ABTD_atomic_release_store_uint32(&p_queue->low_mutex, 0); --} -- --static inline void ABTI_ythread_htable_add_h_node(ABTI_ythread_htable *p_htable, -- ABTI_ythread_queue *p_node) --{ -- ABTI_ythread_queue *p_curr = p_htable->h_list; -- if (!p_curr) { -- p_node->p_h_next = p_node; -- p_node->p_h_prev = p_node; -- p_htable->h_list = p_node; -- } else if (!p_node->p_h_next) { -- p_node->p_h_next = p_curr; -- p_node->p_h_prev = p_curr->p_h_prev; -- p_curr->p_h_prev->p_h_next = p_node; -- p_curr->p_h_prev = p_node; -- } --} -- --static inline void ABTI_ythread_htable_del_h_head(ABTI_ythread_htable *p_htable) --{ -- ABTI_ythread_queue *p_prev, *p_next; -- ABTI_ythread_queue *p_node = p_htable->h_list; -- -- if (p_node == p_node->p_h_next) { -- p_node->p_h_next = NULL; -- p_node->p_h_prev = NULL; -- p_htable->h_list = NULL; -- } else { -- p_prev = p_node->p_h_prev; -- p_next = p_node->p_h_next; -- p_prev->p_h_next = p_next; -- p_next->p_h_prev = p_prev; -- p_node->p_h_next = NULL; -- p_node->p_h_prev = NULL; -- p_htable->h_list = p_next; -- } --} -- --static inline void ABTI_ythread_htable_add_l_node(ABTI_ythread_htable *p_htable, -- ABTI_ythread_queue *p_node) --{ -- ABTI_ythread_queue *p_curr = p_htable->l_list; -- if (!p_curr) { -- p_node->p_l_next = p_node; -- p_node->p_l_prev = p_node; -- p_htable->l_list = p_node; -- } else if (!p_node->p_l_next) { -- p_node->p_l_next = p_curr; -- p_node->p_l_prev = p_curr->p_l_prev; -- p_curr->p_l_prev->p_l_next = p_node; -- p_curr->p_l_prev = p_node; -- } --} -- --static inline void ABTI_ythread_htable_del_l_head(ABTI_ythread_htable *p_htable) --{ -- ABTI_ythread_queue *p_prev, *p_next; -- ABTI_ythread_queue *p_node = p_htable->l_list; -- -- if (p_node == p_node->p_l_next) { -- p_node->p_l_next = NULL; -- p_node->p_l_prev = NULL; -- p_htable->l_list = NULL; -- } else { -- p_prev = p_node->p_l_prev; -- p_next = p_node->p_l_next; -- p_prev->p_l_next = p_next; -- p_next->p_l_prev = p_prev; -- p_node->p_l_next = NULL; -- p_node->p_l_prev = NULL; -- p_htable->l_list = p_next; -- } --} -- --#endif /* ABTI_YTHREAD_HTABLE_H_INCLUDED */ -diff --git a/src/include/abtu.h b/src/include/abtu.h -index 96131b6..afb07c5 100644 ---- a/src/include/abtu.h -+++ b/src/include/abtu.h -@@ -11,6 +11,97 @@ - #include - #include "abt_config.h" - -+/* Basic math functions */ -+static inline int ABTU_max_int(int a, int b) -+{ -+ return a > b ? a : b; -+} -+ -+static inline int32_t ABTU_max_int32(int32_t a, int32_t b) -+{ -+ return a > b ? a : b; -+} -+ -+static inline uint32_t ABTU_max_uint32(uint32_t a, uint32_t b) -+{ -+ return a > b ? a : b; -+} -+ -+static inline int64_t ABTU_max_int64(int64_t a, int64_t b) -+{ -+ return a > b ? a : b; -+} -+ -+static inline uint64_t ABTU_max_uint64(uint64_t a, uint64_t b) -+{ -+ return a > b ? a : b; -+} -+ -+static inline size_t ABTU_max_size(size_t a, size_t b) -+{ -+ return a > b ? a : b; -+} -+ -+static inline int ABTU_min_int(int a, int b) -+{ -+ return a < b ? a : b; -+} -+ -+static inline int32_t ABTU_min_int32(int32_t a, int32_t b) -+{ -+ return a < b ? a : b; -+} -+ -+static inline uint32_t ABTU_min_uint32(uint32_t a, uint32_t b) -+{ -+ return a < b ? a : b; -+} -+ -+static inline int64_t ABTU_min_int64(int64_t a, int64_t b) -+{ -+ return a < b ? a : b; -+} -+ -+static inline uint64_t ABTU_min_uint64(uint64_t a, uint64_t b) -+{ -+ return a < b ? a : b; -+} -+ -+static inline size_t ABTU_min_size(size_t a, size_t b) -+{ -+ return a < b ? a : b; -+} -+ -+static inline uint32_t ABTU_roundup_uint32(uint32_t val, uint32_t multiple) -+{ -+ if ((multiple & (multiple - 1)) == 0) { -+ /* If multiple is a power of two. */ -+ return (val + multiple - 1) & (~(multiple - 1)); -+ } else { -+ return ((val + multiple - 1) / multiple) * multiple; -+ } -+} -+ -+static inline uint64_t ABTU_roundup_uint64(uint64_t val, uint64_t multiple) -+{ -+ if ((multiple & (multiple - 1)) == 0) { -+ /* If multiple is a power of two. */ -+ return (val + multiple - 1) & (~(multiple - 1)); -+ } else { -+ return ((val + multiple - 1) / multiple) * multiple; -+ } -+} -+ -+static inline size_t ABTU_roundup_size(size_t val, size_t multiple) -+{ -+ if ((multiple & (multiple - 1)) == 0) { -+ /* If multiple is a power of two. */ -+ return (val + multiple - 1) & (~(multiple - 1)); -+ } else { -+ return ((val + multiple - 1) / multiple) * multiple; -+ } -+} -+ - /* Utility feature */ - - #ifdef HAVE___BUILTIN_EXPECT -@@ -41,9 +132,7 @@ - #define ABTU_alignof(type) 16 /* 16 bytes would be a good guess. */ - #endif - #define ABTU_MAX_ALIGNMENT \ -- (ABTU_alignof(long double) > ABTU_alignof(long long) \ -- ? ABTU_alignof(long double) \ -- : ABTU_alignof(long long)) -+ ABTU_max_size(ABTU_alignof(long double), ABTU_alignof(long long)) - - #ifdef HAVE_FUNC_ATTRIBUTE_WARN_UNUSED_RESULT - #define ABTU_ret_err __attribute__((warn_unused_result)) -@@ -131,8 +220,7 @@ ABTU_ret_err static inline int ABTU_malloc(size_t size, void **p_ptr) - /* Round up to the smallest multiple of ABT_CONFIG_STATIC_CACHELINE_SIZE - * which is greater than or equal to size in order to avoid any - * false-sharing. */ -- size = (size + ABT_CONFIG_STATIC_CACHELINE_SIZE - 1) & -- (~(ABT_CONFIG_STATIC_CACHELINE_SIZE - 1)); -+ size = ABTU_roundup_size(size, ABT_CONFIG_STATIC_CACHELINE_SIZE); - return ABTU_memalign(ABT_CONFIG_STATIC_CACHELINE_SIZE, size, p_ptr); - } - -@@ -157,7 +245,7 @@ ABTU_ret_err static inline int ABTU_realloc(size_t old_size, size_t new_size, - if (ABTI_IS_ERROR_CHECK_ENABLED && ret != ABT_SUCCESS) { - return ABT_ERR_MEM; - } -- memcpy(new_ptr, old_ptr, (old_size < new_size) ? old_size : new_size); -+ memcpy(new_ptr, old_ptr, ABTU_min_size(old_size, new_size)); - ABTU_free(old_ptr); - *p_ptr = new_ptr; - return ABT_SUCCESS; -@@ -217,4 +305,13 @@ ABTU_alloc_largepage(size_t size, size_t alignment_hint, - void **p_ptr); - void ABTU_free_largepage(void *ptr, size_t size, ABTU_MEM_LARGEPAGE_TYPE type); - -+/* String-to-integer functions. */ -+ABTU_ret_err int ABTU_atoi(const char *str, int *p_val, ABT_bool *p_overflow); -+ABTU_ret_err int ABTU_atoui32(const char *str, uint32_t *p_val, -+ ABT_bool *p_overflow); -+ABTU_ret_err int ABTU_atoui64(const char *str, uint64_t *p_val, -+ ABT_bool *p_overflow); -+ABTU_ret_err int ABTU_atosz(const char *str, size_t *p_val, -+ ABT_bool *p_overflow); -+ - #endif /* ABTU_H_INCLUDED */ -diff --git a/src/info.c b/src/info.c -index cb48385..a83099e 100644 ---- a/src/info.c -+++ b/src/info.c -@@ -105,6 +105,16 @@ static void info_trigger_print_all_thread_stacks( - * - ABT_INFO_QUERY_KIND_ENABLED_TOOL - * \c val must be a pointer to a variable of the type ABT_bool. ABT_TRUE is - * set to \c *val if the tool is enabled. Otherwise, ABT_FALSE is set. -+ * - ABT_INFO_QUERY_KIND_FCONTEXT -+ * \c val must be a pointer to a variable of the type ABT_bool. ABT_TRUE is -+ * set to \c *val if fcontext is used. Otherwise, ABT_FALSE is set. -+ * - ABT_INFO_QUERY_KIND_DYNAMIC_PROMOTION -+ * \c val must be a pointer to a variable of the type ABT_bool. ABT_TRUE is -+ * set to \c *val if dynamic promotion is used. Otherwise, ABT_FALSE is set. -+ * - ABT_INFO_QUERY_KIND_ENABLED_STACK_UNWIND -+ * \c val must be a pointer to a variable of the type ABT_bool. ABT_TRUE is -+ * set to \c *val if the stack unwinding feature is enabled. Otherwise, -+ * ABT_FALSE is set. - * - * @param[in] query_kind query kind - * @param[out] val a pointer to a result -@@ -115,10 +125,9 @@ static void info_trigger_print_all_thread_stacks( - */ - int ABT_info_query_config(ABT_info_query_kind query_kind, void *val) - { -- ABTI_SETUP_WITH_INIT_CHECK(); -- - switch (query_kind) { - case ABT_INFO_QUERY_KIND_ENABLED_DEBUG: -+ ABTI_SETUP_WITH_INIT_CHECK(); - *((ABT_bool *)val) = gp_ABTI_global->use_debug; - break; - case ABT_INFO_QUERY_KIND_ENABLED_PRINT_ERRNO: -@@ -129,6 +138,7 @@ int ABT_info_query_config(ABT_info_query_kind query_kind, void *val) - #endif - break; - case ABT_INFO_QUERY_KIND_ENABLED_LOG: -+ ABTI_SETUP_WITH_INIT_CHECK(); - *((ABT_bool *)val) = gp_ABTI_global->use_logging; - break; - case ABT_INFO_QUERY_KIND_ENABLED_VALGRIND: -@@ -152,10 +162,11 @@ int ABT_info_query_config(ABT_info_query_kind query_kind, void *val) - *((ABT_bool *)val) = ABT_FALSE; - break; - case ABT_INFO_QUERY_KIND_ENABLED_PRESERVE_FPU: --#ifdef ABTD_FCONTEXT_PRESERVE_FPU -- *((ABT_bool *)val) = ABT_TRUE; --#else -+#if !defined(ABTD_FCONTEXT_PRESERVE_FPU) && defined(ABT_CONFIG_USE_FCONTEXT) - *((ABT_bool *)val) = ABT_FALSE; -+#else -+ /* If ucontext is used, FPU is preserved. */ -+ *((ABT_bool *)val) = ABT_TRUE; - #endif - break; - case ABT_INFO_QUERY_KIND_ENABLED_THREAD_CANCEL: -@@ -197,24 +208,31 @@ int ABT_info_query_config(ABT_info_query_kind query_kind, void *val) - #endif - break; - case ABT_INFO_QUERY_KIND_ENABLED_PRINT_CONFIG: -+ ABTI_SETUP_WITH_INIT_CHECK(); - *((ABT_bool *)val) = gp_ABTI_global->print_config; - break; - case ABT_INFO_QUERY_KIND_ENABLED_AFFINITY: -+ ABTI_SETUP_WITH_INIT_CHECK(); - *((ABT_bool *)val) = gp_ABTI_global->set_affinity; - break; - case ABT_INFO_QUERY_KIND_MAX_NUM_XSTREAMS: -+ ABTI_SETUP_WITH_INIT_CHECK(); - *((unsigned int *)val) = gp_ABTI_global->max_xstreams; - break; - case ABT_INFO_QUERY_KIND_DEFAULT_THREAD_STACKSIZE: -+ ABTI_SETUP_WITH_INIT_CHECK(); - *((size_t *)val) = gp_ABTI_global->thread_stacksize; - break; - case ABT_INFO_QUERY_KIND_DEFAULT_SCHED_STACKSIZE: -+ ABTI_SETUP_WITH_INIT_CHECK(); - *((size_t *)val) = gp_ABTI_global->sched_stacksize; - break; - case ABT_INFO_QUERY_KIND_DEFAULT_SCHED_EVENT_FREQ: -+ ABTI_SETUP_WITH_INIT_CHECK(); - *((uint64_t *)val) = gp_ABTI_global->sched_event_freq; - break; - case ABT_INFO_QUERY_KIND_DEFAULT_SCHED_SLEEP_NSEC: -+ ABTI_SETUP_WITH_INIT_CHECK(); - *((uint64_t *)val) = gp_ABTI_global->sched_sleep_nsec; - break; - case ABT_INFO_QUERY_KIND_ENABLED_TOOL: -@@ -224,6 +242,27 @@ int ABT_info_query_config(ABT_info_query_kind query_kind, void *val) - *((ABT_bool *)val) = ABT_FALSE; - #endif - break; -+ case ABT_INFO_QUERY_KIND_FCONTEXT: -+#ifdef ABT_CONFIG_USE_FCONTEXT -+ *((ABT_bool *)val) = ABT_TRUE; -+#else -+ *((ABT_bool *)val) = ABT_FALSE; -+#endif -+ break; -+ case ABT_INFO_QUERY_KIND_DYNAMIC_PROMOTION: -+#if ABT_CONFIG_THREAD_TYPE == ABT_THREAD_TYPE_DYNAMIC_PROMOTION -+ *((ABT_bool *)val) = ABT_TRUE; -+#else -+ *((ABT_bool *)val) = ABT_FALSE; -+#endif -+ break; -+ case ABT_INFO_QUERY_KIND_ENABLED_STACK_UNWIND: -+#ifdef ABT_CONFIG_ENABLE_STACK_UNWIND -+ *((ABT_bool *)val) = ABT_TRUE; -+#else -+ *((ABT_bool *)val) = ABT_FALSE; -+#endif -+ break; - default: - ABTI_HANDLE_ERROR(ABT_ERR_INV_QUERY_KIND); - break; -@@ -240,13 +279,15 @@ int ABT_info_query_config(ABT_info_query_kind query_kind, void *val) - * - * @param[in] fp output stream - * @return Error code -- * @retval ABT_SUCCESS on success -- * @retval ABT_ERR_UNINITIALIZED Argobots has not been initialized -+ * @retval ABT_SUCCESS on success - */ - int ABT_info_print_config(FILE *fp) - { -- ABTI_SETUP_WITH_INIT_CHECK(); -- -+ if (!gp_ABTI_global) { -+ fprintf(fp, "Argobots is not initialized.\n"); -+ fflush(fp); -+ return ABT_SUCCESS; -+ } - ABTI_info_print_config(fp); - return ABT_SUCCESS; - } -@@ -260,13 +301,15 @@ int ABT_info_print_config(FILE *fp) - * - * @param[in] fp output stream - * @return Error code -- * @retval ABT_SUCCESS on success -- * @retval ABT_ERR_UNINITIALIZED Argobots has not been initialized -+ * @retval ABT_SUCCESS on success - */ - int ABT_info_print_all_xstreams(FILE *fp) - { -- ABTI_SETUP_WITH_INIT_CHECK(); -- -+ if (!gp_ABTI_global) { -+ fprintf(fp, "Argobots is not initialized.\n"); -+ fflush(fp); -+ return ABT_SUCCESS; -+ } - ABTI_global *p_global = gp_ABTI_global; - - ABTI_spinlock_acquire(&p_global->xstream_list_lock); -@@ -300,8 +343,6 @@ int ABT_info_print_all_xstreams(FILE *fp) - int ABT_info_print_xstream(FILE *fp, ABT_xstream xstream) - { - ABTI_xstream *p_xstream = ABTI_xstream_get_ptr(xstream); -- ABTI_CHECK_NULL_XSTREAM_PTR(p_xstream); -- - ABTI_xstream_print(p_xstream, fp, 0, ABT_FALSE); - return ABT_SUCCESS; - } -@@ -321,8 +362,6 @@ int ABT_info_print_xstream(FILE *fp, ABT_xstream xstream) - int ABT_info_print_sched(FILE *fp, ABT_sched sched) - { - ABTI_sched *p_sched = ABTI_sched_get_ptr(sched); -- ABTI_CHECK_NULL_SCHED_PTR(p_sched); -- - ABTI_sched_print(p_sched, fp, 0, ABT_TRUE); - return ABT_SUCCESS; - } -@@ -342,8 +381,6 @@ int ABT_info_print_sched(FILE *fp, ABT_sched sched) - int ABT_info_print_pool(FILE *fp, ABT_pool pool) - { - ABTI_pool *p_pool = ABTI_pool_get_ptr(pool); -- ABTI_CHECK_NULL_POOL_PTR(p_pool); -- - ABTI_pool_print(p_pool, fp, 0); - return ABT_SUCCESS; - } -@@ -363,8 +400,6 @@ int ABT_info_print_pool(FILE *fp, ABT_pool pool) - int ABT_info_print_thread(FILE *fp, ABT_thread thread) - { - ABTI_thread *p_thread = ABTI_thread_get_ptr(thread); -- ABTI_CHECK_NULL_THREAD_PTR(p_thread); -- - ABTI_thread_print(p_thread, fp, 0); - return ABT_SUCCESS; - } -@@ -385,8 +420,6 @@ int ABT_info_print_thread(FILE *fp, ABT_thread thread) - int ABT_info_print_thread_attr(FILE *fp, ABT_thread_attr attr) - { - ABTI_thread_attr *p_attr = ABTI_thread_attr_get_ptr(attr); -- ABTI_CHECK_NULL_THREAD_ATTR_PTR(p_attr); -- - ABTI_thread_attr_print(p_attr, fp, 0); - return ABT_SUCCESS; - } -@@ -422,11 +455,19 @@ int ABT_info_print_task(FILE *fp, ABT_task task); - int ABT_info_print_thread_stack(FILE *fp, ABT_thread thread) - { - ABTI_thread *p_thread = ABTI_thread_get_ptr(thread); -- ABTI_CHECK_NULL_THREAD_PTR(p_thread); -- ABTI_ythread *p_ythread; -- ABTI_CHECK_YIELDABLE(p_thread, &p_ythread, ABT_ERR_INV_THREAD); -- -- ABTI_ythread_print_stack(p_ythread, fp); -+ if (!p_thread) { -+ fprintf(fp, "no stack\n"); -+ fflush(0); -+ } else { -+ ABTI_ythread *p_ythread; -+ if (p_thread->type & ABTI_THREAD_TYPE_YIELDABLE) { -+ p_ythread = ABTI_thread_get_ythread(p_thread); -+ ABTI_ythread_print_stack(p_ythread, fp); -+ } else { -+ fprintf(fp, "no stack\n"); -+ fflush(0); -+ } -+ } - return ABT_SUCCESS; - } - -@@ -446,8 +487,6 @@ int ABT_info_print_thread_stack(FILE *fp, ABT_thread thread) - int ABT_info_print_thread_stacks_in_pool(FILE *fp, ABT_pool pool) - { - ABTI_pool *p_pool = ABTI_pool_get_ptr(pool); -- ABTI_CHECK_NULL_POOL_PTR(p_pool); -- - int abt_errno = info_print_thread_stacks_in_pool(fp, p_pool); - ABTI_CHECK_ERROR(abt_errno); - return ABT_SUCCESS; -@@ -508,23 +547,23 @@ ABTU_ret_err static int print_all_thread_stacks(FILE *fp); - #define PRINT_STACK_FLAG_WAIT 2 - #define PRINT_STACK_FLAG_FINALIZE 3 - --static ABTD_atomic_uint32 print_stack_flag = -- ABTD_ATOMIC_UINT32_STATIC_INITIALIZER(PRINT_STACK_FLAG_UNSET); -+static ABTD_atomic_int print_stack_flag = -+ ABTD_ATOMIC_INT_STATIC_INITIALIZER(PRINT_STACK_FLAG_UNSET); - static FILE *print_stack_fp = NULL; - static double print_stack_timeout = 0.0; - static void (*print_cb_func)(ABT_bool, void *) = NULL; - static void *print_arg = NULL; --static ABTD_atomic_uint32 print_stack_barrier = -- ABTD_ATOMIC_UINT32_STATIC_INITIALIZER(0); -+static ABTD_atomic_int print_stack_barrier = -+ ABTD_ATOMIC_INT_STATIC_INITIALIZER(0); - - void ABTI_info_check_print_all_thread_stacks(void) - { -- if (ABTD_atomic_acquire_load_uint32(&print_stack_flag) != -+ if (ABTD_atomic_acquire_load_int(&print_stack_flag) != - PRINT_STACK_FLAG_WAIT) - return; - - /* Wait for the other execution streams using a barrier mechanism. */ -- uint32_t self_value = ABTD_atomic_fetch_add_uint32(&print_stack_barrier, 1); -+ int self_value = ABTD_atomic_fetch_add_int(&print_stack_barrier, 1); - if (self_value == 0) { - /* This ES becomes the main ES. */ - double start_time = ABTI_get_wtime(); -@@ -534,7 +573,7 @@ void ABTI_info_check_print_all_thread_stacks(void) - * printing data. */ - ABTI_spinlock_acquire(&gp_ABTI_global->xstream_list_lock); - while (1) { -- if (ABTD_atomic_acquire_load_uint32(&print_stack_barrier) >= -+ if (ABTD_atomic_acquire_load_int(&print_stack_barrier) >= - gp_ABTI_global->num_xstreams) { - break; - } -@@ -554,35 +593,36 @@ void ABTI_info_check_print_all_thread_stacks(void) - fprintf(print_stack_fp, - "ABT_info_trigger_print_all_thread_stacks: " - "timeout (only %d ESs stop)\n", -- (int)ABTD_atomic_acquire_load_uint32(&print_stack_barrier)); -+ ABTD_atomic_acquire_load_int(&print_stack_barrier)); - } - int abt_errno = print_all_thread_stacks(print_stack_fp); - if (ABTI_IS_ERROR_CHECK_ENABLED && abt_errno != ABT_SUCCESS) { - fprintf(print_stack_fp, "ABT_info_trigger_print_all_thread_stacks: " - "failed because of an internal error.\n"); - } -+ fflush(print_stack_fp); - /* Release the lock that protects ES data. */ - ABTI_spinlock_release(&gp_ABTI_global->xstream_list_lock); - if (print_cb_func) - print_cb_func(force_print, print_arg); - /* Update print_stack_flag to 3. */ -- ABTD_atomic_release_store_uint32(&print_stack_flag, -- PRINT_STACK_FLAG_FINALIZE); -+ ABTD_atomic_release_store_int(&print_stack_flag, -+ PRINT_STACK_FLAG_FINALIZE); - } else { - /* Wait for the main ES's work. */ -- while (ABTD_atomic_acquire_load_uint32(&print_stack_flag) != -+ while (ABTD_atomic_acquire_load_int(&print_stack_flag) != - PRINT_STACK_FLAG_FINALIZE) - ABTD_atomic_pause(); - } -- ABTI_ASSERT(ABTD_atomic_acquire_load_uint32(&print_stack_flag) == -+ ABTI_ASSERT(ABTD_atomic_acquire_load_int(&print_stack_flag) == - PRINT_STACK_FLAG_FINALIZE); - - /* Decrement the barrier value. */ -- uint32_t dec_value = ABTD_atomic_fetch_sub_uint32(&print_stack_barrier, 1); -+ int dec_value = ABTD_atomic_fetch_sub_int(&print_stack_barrier, 1); - if (dec_value == 0) { - /* The last execution stream resets the flag. */ -- ABTD_atomic_release_store_uint32(&print_stack_flag, -- PRINT_STACK_FLAG_UNSET); -+ ABTD_atomic_release_store_int(&print_stack_flag, -+ PRINT_STACK_FLAG_UNSET); - } - } - -@@ -591,10 +631,10 @@ void ABTI_info_print_config(FILE *fp) - ABTI_global *p_global = gp_ABTI_global; - - fprintf(fp, "Argobots Configuration:\n"); -+ fprintf(fp, " - version: " ABT_VERSION "\n"); - fprintf(fp, " - # of cores: %d\n", p_global->num_cores); -- fprintf(fp, " - cache line size: %u\n", ABT_CONFIG_STATIC_CACHELINE_SIZE); -- fprintf(fp, " - OS page size: %u\n", p_global->os_page_size); -- fprintf(fp, " - huge page size: %u\n", p_global->huge_page_size); -+ fprintf(fp, " - cache line size: %u B\n", ABT_CONFIG_STATIC_CACHELINE_SIZE); -+ fprintf(fp, " - huge page size: %zu B\n", p_global->huge_page_size); - fprintf(fp, " - max. # of ESs: %d\n", p_global->max_xstreams); - fprintf(fp, " - cur. # of ESs: %d\n", p_global->num_xstreams); - fprintf(fp, " - ES affinity: %s\n", -@@ -603,13 +643,98 @@ void ABTI_info_print_config(FILE *fp) - (p_global->use_logging == ABT_TRUE) ? "on" : "off"); - fprintf(fp, " - debug output: %s\n", - (p_global->use_debug == ABT_TRUE) ? "on" : "off"); -- fprintf(fp, " - key table entries: %d\n", p_global->key_table_size); -- fprintf(fp, " - ULT stack size: %u KB\n", -- (unsigned)(p_global->thread_stacksize / 1024)); -- fprintf(fp, " - scheduler stack size: %u KB\n", -- (unsigned)(p_global->sched_stacksize / 1024)); -- fprintf(fp, " - scheduler event check frequency: %u\n", -+ fprintf(fp, " - print errno: " -+#ifdef ABT_CONFIG_PRINT_ABT_ERRNO -+ "on" -+#else -+ "off" -+#endif -+ "\n"); -+ fprintf(fp, " - valgrind support: " -+#ifdef HAVE_VALGRIND_SUPPORT -+ "yes" -+#else -+ "no" -+#endif -+ "\n"); -+ fprintf(fp, " - thread cancellation: " -+#ifndef ABT_CONFIG_DISABLE_THREAD_CANCEL -+ "enabled" -+#else -+ "disabled" -+#endif -+ "\n"); -+ fprintf(fp, " - task cancellation: " -+#ifndef ABT_CONFIG_DISABLE_TASK_CANCEL -+ "enabled" -+#else -+ "disabled" -+#endif -+ "\n"); -+ fprintf(fp, " - thread migration: " -+#ifndef ABT_CONFIG_DISABLE_MIGRATION -+ "enabled" -+#else -+ "disabled" -+#endif -+ "\n"); -+ fprintf(fp, " - external thread: " -+#ifndef ABT_CONFIG_DISABLE_EXT_THREAD -+ "enabled" -+#else -+ "disabled" -+#endif -+ "\n"); -+ fprintf(fp, " - error check: " -+#ifndef ABT_CONFIG_DISABLE_ERROR_CHECK -+ "enabled" -+#else -+ "disable" -+#endif -+ "\n"); -+ fprintf(fp, " - tool interface: " -+#ifndef ABT_CONFIG_DISABLE_TOOL_INTERFACE -+ "yes" -+#else -+ "no" -+#endif -+ "\n"); -+ fprintf(fp, " - context-switch: " -+#ifdef ABT_CONFIG_USE_FCONTEXT -+ "fcontext" -+#if ABT_CONFIG_THREAD_TYPE == ABT_THREAD_TYPE_DYNAMIC_PROMOTION && \ -+ defined(ABTD_FCONTEXT_PRESERVE_FPU) -+ " (dynamic-promotion)" -+#elif ABT_CONFIG_THREAD_TYPE == ABT_THREAD_TYPE_DYNAMIC_PROMOTION && \ -+ !defined(ABTD_FCONTEXT_PRESERVE_FPU) -+ " (dynamic-promotion, no FPU save)" -+#elif ABT_CONFIG_THREAD_TYPE != ABT_THREAD_TYPE_DYNAMIC_PROMOTION && \ -+ !defined(ABTD_FCONTEXT_PRESERVE_FPU) -+ " (no FPU save)" -+#endif /* ABT_CONFIG_THREAD_TYPE, ABTD_FCONTEXT_PRESERVE_FPU */ -+ -+#else /* ABT_CONFIG_USE_FCONTEXT */ -+ "ucontext" -+#endif /* !ABT_CONFIG_USE_FCONTEXT */ -+ "\n"); -+ -+ fprintf(fp, " - key table entries: %" PRIu32 "\n", -+ p_global->key_table_size); -+ fprintf(fp, " - default ULT stack size: %zu KB\n", -+ p_global->thread_stacksize / 1024); -+ fprintf(fp, " - default scheduler stack size: %zu KB\n", -+ p_global->sched_stacksize / 1024); -+ fprintf(fp, " - default scheduler event check frequency: %u\n", - p_global->sched_event_freq); -+ fprintf(fp, " - default scheduler sleep: " -+#ifdef ABT_CONFIG_USE_SCHED_SLEEP -+ "on" -+#else -+ "off" -+#endif -+ "\n"); -+ fprintf(fp, " - default scheduler sleep duration : %" PRIu64 " [ns]\n", -+ p_global->sched_sleep_nsec); - - fprintf(fp, " - timer function: " - #if defined(ABT_CONFIG_USE_CLOCK_GETTIME) -@@ -623,10 +748,11 @@ void ABTI_info_print_config(FILE *fp) - - #ifdef ABT_CONFIG_USE_MEM_POOL - fprintf(fp, "Memory Pool:\n"); -- fprintf(fp, " - page size for allocation: %u KB\n", -+ fprintf(fp, " - page size for allocation: %zu KB\n", - p_global->mem_page_size / 1024); -- fprintf(fp, " - stack page size: %u KB\n", p_global->mem_sp_size / 1024); -+ fprintf(fp, " - stack page size: %zu KB\n", p_global->mem_sp_size / 1024); - fprintf(fp, " - max. # of stacks per ES: %u\n", p_global->mem_max_stacks); -+ fprintf(fp, " - max. # of descs per ES: %u\n", p_global->mem_max_descs); - switch (p_global->mem_lp_alloc) { - case ABTI_MEM_LP_MALLOC: - fprintf(fp, " - large page allocation: malloc\n"); -@@ -685,11 +811,6 @@ static void info_print_unit(void *arg, ABT_unit unit) - "id : %" PRIu64 "\n" - "ctx : %p\n", - (uint64_t)thread_id, (void *)&p_ythread->ctx); -- ABTD_ythread_print_context(p_ythread, fp, 2); -- fprintf(fp, -- "stack : %p\n" -- "stacksize : %" PRIu64 "\n", -- p_ythread->p_stack, (uint64_t)p_ythread->stacksize); - ABTI_ythread_print_stack(p_ythread, fp); - } else if (type == ABT_UNIT_TYPE_TASK) { - fprintf(fp, "=== tasklet (%p) ===\n", (void *)unit); -@@ -701,6 +822,12 @@ static void info_print_unit(void *arg, ABT_unit unit) - ABTU_ret_err static int info_print_thread_stacks_in_pool(FILE *fp, - ABTI_pool *p_pool) - { -+ if (p_pool == NULL) { -+ fprintf(fp, "== NULL pool ==\n"); -+ fflush(fp); -+ return ABT_SUCCESS; -+ } -+ - ABT_pool pool = ABTI_pool_get_handle(p_pool); - - if (!p_pool->p_print_all) { -@@ -711,6 +838,7 @@ ABTU_ret_err static int info_print_thread_stacks_in_pool(FILE *fp, - arg.fp = fp; - arg.pool = pool; - p_pool->p_print_all(pool, &arg, info_print_unit); -+ fflush(fp); - return ABT_SUCCESS; - } - -@@ -757,28 +885,29 @@ static void info_trigger_print_all_thread_stacks( - { - /* This function is signal-safe, so it may not call other functions unless - * you really know what the called functions do. */ -- if (ABTD_atomic_acquire_load_uint32(&print_stack_flag) == -+ if (ABTD_atomic_acquire_load_int(&print_stack_flag) == - PRINT_STACK_FLAG_UNSET) { -- if (ABTD_atomic_bool_cas_strong_uint32(&print_stack_flag, -- PRINT_STACK_FLAG_UNSET, -- PRINT_STACK_FLAG_INITIALIZE)) { -+ if (ABTD_atomic_bool_cas_strong_int(&print_stack_flag, -+ PRINT_STACK_FLAG_UNSET, -+ PRINT_STACK_FLAG_INITIALIZE)) { - /* Save fp and timeout. */ - print_stack_fp = fp; - print_stack_timeout = timeout; - print_cb_func = cb_func; - print_arg = arg; - /* Here print_stack_barrier must be 0. */ -- ABTI_ASSERT(ABTD_atomic_acquire_load_uint32(&print_stack_barrier) == -+ ABTI_ASSERT(ABTD_atomic_acquire_load_int(&print_stack_barrier) == - 0); -- ABTD_atomic_release_store_uint32(&print_stack_flag, -- PRINT_STACK_FLAG_WAIT); -+ ABTD_atomic_release_store_int(&print_stack_flag, -+ PRINT_STACK_FLAG_WAIT); - } - } - } - - ABTU_ret_err static int print_all_thread_stacks(FILE *fp) - { -- int i, abt_errno; -+ size_t i; -+ int abt_errno; - struct info_pool_set_t pool_set; - - abt_errno = info_initialize_pool_set(&pool_set); -@@ -794,7 +923,7 @@ ABTU_ret_err static int print_all_thread_stacks(FILE *fp) - for (i = 0; i < p_main_sched->num_pools; i++) { - ABT_pool pool = p_main_sched->pools[i]; - ABTI_ASSERT(pool != ABT_POOL_NULL); -- fprintf(fp, " pools[%d] : %p\n", i, -+ fprintf(fp, " pools[%zu] : %p\n", i, - (void *)ABTI_pool_get_ptr(pool)); - abt_errno = info_add_pool_set(pool, &pool_set); - if (ABTI_IS_ERROR_CHECK_ENABLED && abt_errno != ABT_SUCCESS) { -diff --git a/src/mem/malloc.c b/src/mem/malloc.c -index e374356..c113fb0 100644 ---- a/src/mem/malloc.c -+++ b/src/mem/malloc.c -@@ -47,9 +47,9 @@ void ABTI_mem_init(ABTI_global *p_global) - size_t thread_stacksize = p_global->thread_stacksize; - ABTI_ASSERT((thread_stacksize & (ABT_CONFIG_STATIC_CACHELINE_SIZE - 1)) == - 0); -- size_t stacksize = (thread_stacksize + sizeof(ABTI_ythread) + -- ABT_CONFIG_STATIC_CACHELINE_SIZE - 1) & -- (~(ABT_CONFIG_STATIC_CACHELINE_SIZE - 1)); -+ size_t stacksize = -+ ABTU_roundup_size(thread_stacksize + sizeof(ABTI_ythread), -+ ABT_CONFIG_STATIC_CACHELINE_SIZE); - if ((stacksize & (2 * ABT_CONFIG_STATIC_CACHELINE_SIZE - 1)) == 0) { - /* Avoid a multiple of 2 * cacheline size to avoid cache bank conflict. - */ -diff --git a/src/mem/mem_pool.c b/src/mem/mem_pool.c -index 2a82f5a..e45dee3 100644 ---- a/src/mem/mem_pool.c -+++ b/src/mem/mem_pool.c -@@ -75,10 +75,10 @@ mem_pool_return_partial_bucket(ABTI_mem_pool_global_pool *p_global_pool, - } - - void ABTI_mem_pool_init_global_pool( -- ABTI_mem_pool_global_pool *p_global_pool, int num_headers_per_bucket, -+ ABTI_mem_pool_global_pool *p_global_pool, size_t num_headers_per_bucket, - size_t header_size, size_t header_offset, size_t page_size, -- const ABTU_MEM_LARGEPAGE_TYPE *lp_type_requests, int num_lp_type_requests, -- size_t alignment_hint) -+ const ABTU_MEM_LARGEPAGE_TYPE *lp_type_requests, -+ uint32_t num_lp_type_requests, size_t alignment_hint) - { - p_global_pool->num_headers_per_bucket = num_headers_per_bucket; - ABTI_ASSERT(header_offset + sizeof(ABTI_mem_pool_header) <= header_size); -@@ -148,7 +148,7 @@ void ABTI_mem_pool_destroy_local_pool(ABTI_mem_pool_local_pool *p_local_pool) - ABTI_mem_pool_return_bucket(p_local_pool->p_global_pool, - p_local_pool->buckets[i]); - } -- const int num_headers_per_bucket = p_local_pool->num_headers_per_bucket; -+ const size_t num_headers_per_bucket = p_local_pool->num_headers_per_bucket; - ABTI_mem_pool_header *cur_bucket = p_local_pool->buckets[bucket_index]; - if (cur_bucket->bucket_info.num_headers == num_headers_per_bucket) { - /* The last bucket is also full. Return the last bucket as well. */ -diff --git a/src/mutex.c b/src/mutex.c -index 79b7125..3748ff9 100644 ---- a/src/mutex.c -+++ b/src/mutex.c -@@ -4,10 +4,6 @@ - */ - - #include "abti.h" --#include "abti_ythread_htable.h" -- --static inline void mutex_lock_low(ABTI_local **pp_local, ABTI_mutex *p_mutex); --static inline void mutex_unlock_se(ABTI_local **pp_local, ABTI_mutex *p_mutex); - - /** @defgroup MUTEX Mutex - * Mutex is a synchronization method to support mutual exclusion between ULTs. -@@ -37,16 +33,11 @@ static inline void mutex_unlock_se(ABTI_local **pp_local, ABTI_mutex *p_mutex); - */ - int ABT_mutex_create(ABT_mutex *newmutex) - { -- int abt_errno; - ABTI_mutex *p_newmutex; - -- abt_errno = ABTU_calloc(1, sizeof(ABTI_mutex), (void **)&p_newmutex); -+ int abt_errno = ABTU_malloc(sizeof(ABTI_mutex), (void **)&p_newmutex); - ABTI_CHECK_ERROR(abt_errno); -- abt_errno = ABTI_mutex_init(p_newmutex); -- if (ABTI_IS_ERROR_CHECK_ENABLED && abt_errno != ABT_SUCCESS) { -- ABTU_free(p_newmutex); -- ABTI_HANDLE_ERROR(abt_errno); -- } -+ ABTI_mutex_init(p_newmutex); - - /* Return value */ - *newmutex = ABTI_mutex_get_handle(p_newmutex); -@@ -71,18 +62,13 @@ int ABT_mutex_create(ABT_mutex *newmutex) - */ - int ABT_mutex_create_with_attr(ABT_mutex_attr attr, ABT_mutex *newmutex) - { -- int abt_errno; - ABTI_mutex_attr *p_attr = ABTI_mutex_attr_get_ptr(attr); - ABTI_CHECK_NULL_MUTEX_ATTR_PTR(p_attr); - ABTI_mutex *p_newmutex; - -- abt_errno = ABTU_malloc(sizeof(ABTI_mutex), (void **)&p_newmutex); -+ int abt_errno = ABTU_malloc(sizeof(ABTI_mutex), (void **)&p_newmutex); - ABTI_CHECK_ERROR(abt_errno); -- abt_errno = ABTI_mutex_init(p_newmutex); -- if (ABTI_IS_ERROR_CHECK_ENABLED && abt_errno != ABT_SUCCESS) { -- ABTU_free(p_newmutex); -- ABTI_HANDLE_ERROR(abt_errno); -- } -+ ABTI_mutex_init(p_newmutex); - memcpy(&p_newmutex->attr, p_attr, sizeof(ABTI_mutex_attr)); - - /* Return value */ -@@ -111,7 +97,6 @@ int ABT_mutex_free(ABT_mutex *mutex) - ABTI_mutex *p_mutex = ABTI_mutex_get_ptr(h_mutex); - ABTI_CHECK_NULL_MUTEX_PTR(p_mutex); - -- ABTI_mutex_fini(p_mutex); - ABTU_free(p_mutex); - - /* Return value */ -@@ -142,26 +127,7 @@ int ABT_mutex_lock(ABT_mutex mutex) - ABTI_local *p_local = ABTI_local_get_local(); - ABTI_mutex *p_mutex = ABTI_mutex_get_ptr(mutex); - ABTI_CHECK_NULL_MUTEX_PTR(p_mutex); -- -- if (p_mutex->attr.attrs == ABTI_MUTEX_ATTR_NONE) { -- /* default attributes */ -- ABTI_mutex_lock(&p_local, p_mutex); -- -- } else if (p_mutex->attr.attrs & ABTI_MUTEX_ATTR_RECURSIVE) { -- /* recursive mutex */ -- ABTI_thread_id self_id = ABTI_self_get_thread_id(p_local); -- if (self_id != p_mutex->attr.owner_id) { -- ABTI_mutex_lock(&p_local, p_mutex); -- p_mutex->attr.owner_id = self_id; -- ABTI_ASSERT(p_mutex->attr.nesting_cnt == 0); -- } else { -- p_mutex->attr.nesting_cnt++; -- } -- -- } else { -- /* unknown attributes */ -- ABTI_mutex_lock(&p_local, p_mutex); -- } -+ ABTI_mutex_lock(&p_local, p_mutex); - return ABT_SUCCESS; - } - -@@ -183,32 +149,17 @@ int ABT_mutex_lock_low(ABT_mutex mutex) - ABTI_local *p_local = ABTI_local_get_local(); - ABTI_mutex *p_mutex = ABTI_mutex_get_ptr(mutex); - ABTI_CHECK_NULL_MUTEX_PTR(p_mutex); -- -- if (p_mutex->attr.attrs == ABTI_MUTEX_ATTR_NONE) { -- /* default attributes */ -- mutex_lock_low(&p_local, p_mutex); -- -- } else if (p_mutex->attr.attrs & ABTI_MUTEX_ATTR_RECURSIVE) { -- /* recursive mutex */ -- ABTI_thread_id self_id = ABTI_self_get_thread_id(p_local); -- if (self_id != p_mutex->attr.owner_id) { -- mutex_lock_low(&p_local, p_mutex); -- p_mutex->attr.owner_id = self_id; -- ABTI_ASSERT(p_mutex->attr.nesting_cnt == 0); -- } else { -- p_mutex->attr.nesting_cnt++; -- } -- -- } else { -- /* unknown attributes */ -- mutex_lock_low(&p_local, p_mutex); -- } -+ ABTI_mutex_lock(&p_local, p_mutex); - return ABT_SUCCESS; - } - - int ABT_mutex_lock_high(ABT_mutex mutex) - { -- return ABT_mutex_lock(mutex); -+ ABTI_local *p_local = ABTI_local_get_local(); -+ ABTI_mutex *p_mutex = ABTI_mutex_get_ptr(mutex); -+ ABTI_CHECK_NULL_MUTEX_PTR(p_mutex); -+ ABTI_mutex_lock(&p_local, p_mutex); -+ return ABT_SUCCESS; - } - - /** -@@ -230,33 +181,10 @@ int ABT_mutex_lock_high(ABT_mutex mutex) - */ - int ABT_mutex_trylock(ABT_mutex mutex) - { -+ ABTI_local *p_local = ABTI_local_get_local(); - ABTI_mutex *p_mutex = ABTI_mutex_get_ptr(mutex); - ABTI_CHECK_NULL_MUTEX_PTR(p_mutex); -- -- int abt_errno; -- if (p_mutex->attr.attrs == ABTI_MUTEX_ATTR_NONE) { -- /* default attributes */ -- abt_errno = ABTI_mutex_trylock(p_mutex); -- -- } else if (p_mutex->attr.attrs & ABTI_MUTEX_ATTR_RECURSIVE) { -- /* recursive mutex */ -- ABTI_local *p_local = ABTI_local_get_local(); -- ABTI_thread_id self_id = ABTI_self_get_thread_id(p_local); -- if (self_id != p_mutex->attr.owner_id) { -- abt_errno = ABTI_mutex_trylock(p_mutex); -- if (abt_errno == ABT_SUCCESS) { -- p_mutex->attr.owner_id = self_id; -- ABTI_ASSERT(p_mutex->attr.nesting_cnt == 0); -- } -- } else { -- p_mutex->attr.nesting_cnt++; -- abt_errno = ABT_SUCCESS; -- } -- -- } else { -- /* unknown attributes */ -- abt_errno = ABTI_mutex_trylock(p_mutex); -- } -+ int abt_errno = ABTI_mutex_trylock(p_local, p_mutex); - /* Trylock always needs to return an error code. */ - return abt_errno; - } -@@ -277,29 +205,10 @@ int ABT_mutex_trylock(ABT_mutex mutex) - */ - int ABT_mutex_spinlock(ABT_mutex mutex) - { -+ ABTI_local *p_local = ABTI_local_get_local(); - ABTI_mutex *p_mutex = ABTI_mutex_get_ptr(mutex); - ABTI_CHECK_NULL_MUTEX_PTR(p_mutex); -- -- if (p_mutex->attr.attrs == ABTI_MUTEX_ATTR_NONE) { -- /* default attributes */ -- ABTI_mutex_spinlock(p_mutex); -- -- } else if (p_mutex->attr.attrs & ABTI_MUTEX_ATTR_RECURSIVE) { -- /* recursive mutex */ -- ABTI_local *p_local = ABTI_local_get_local(); -- ABTI_thread_id self_id = ABTI_self_get_thread_id(p_local); -- if (self_id != p_mutex->attr.owner_id) { -- ABTI_mutex_spinlock(p_mutex); -- p_mutex->attr.owner_id = self_id; -- ABTI_ASSERT(p_mutex->attr.nesting_cnt == 0); -- } else { -- p_mutex->attr.nesting_cnt++; -- } -- -- } else { -- /* unknown attributes */ -- ABTI_mutex_spinlock(p_mutex); -- } -+ ABTI_mutex_spinlock(p_local, p_mutex); - return ABT_SUCCESS; - } - -@@ -320,27 +229,7 @@ int ABT_mutex_unlock(ABT_mutex mutex) - ABTI_local *p_local = ABTI_local_get_local(); - ABTI_mutex *p_mutex = ABTI_mutex_get_ptr(mutex); - ABTI_CHECK_NULL_MUTEX_PTR(p_mutex); -- -- if (p_mutex->attr.attrs == ABTI_MUTEX_ATTR_NONE) { -- /* default attributes */ -- ABTI_mutex_unlock(p_local, p_mutex); -- -- } else if (p_mutex->attr.attrs & ABTI_MUTEX_ATTR_RECURSIVE) { -- /* recursive mutex */ -- ABTI_CHECK_TRUE(ABTI_self_get_thread_id(p_local) == -- p_mutex->attr.owner_id, -- ABT_ERR_INV_THREAD); -- if (p_mutex->attr.nesting_cnt == 0) { -- p_mutex->attr.owner_id = 0; -- ABTI_mutex_unlock(p_local, p_mutex); -- } else { -- p_mutex->attr.nesting_cnt--; -- } -- -- } else { -- /* unknown attributes */ -- ABTI_mutex_unlock(p_local, p_mutex); -- } -+ ABTI_mutex_unlock(p_local, p_mutex); - return ABT_SUCCESS; - } - -@@ -366,27 +255,7 @@ int ABT_mutex_unlock_se(ABT_mutex mutex) - ABTI_local *p_local = ABTI_local_get_local(); - ABTI_mutex *p_mutex = ABTI_mutex_get_ptr(mutex); - ABTI_CHECK_NULL_MUTEX_PTR(p_mutex); -- -- if (p_mutex->attr.attrs == ABTI_MUTEX_ATTR_NONE) { -- /* default attributes */ -- mutex_unlock_se(&p_local, p_mutex); -- -- } else if (p_mutex->attr.attrs & ABTI_MUTEX_ATTR_RECURSIVE) { -- /* recursive mutex */ -- ABTI_CHECK_TRUE(ABTI_self_get_thread_id(p_local) == -- p_mutex->attr.owner_id, -- ABT_ERR_INV_THREAD); -- if (p_mutex->attr.nesting_cnt == 0) { -- p_mutex->attr.owner_id = 0; -- mutex_unlock_se(&p_local, p_mutex); -- } else { -- p_mutex->attr.nesting_cnt--; -- } -- -- } else { -- /* unknown attributes */ -- mutex_unlock_se(&p_local, p_mutex); -- } -+ ABTI_mutex_unlock(p_local, p_mutex); - return ABT_SUCCESS; - } - -@@ -395,7 +264,6 @@ int ABT_mutex_unlock_de(ABT_mutex mutex) - ABTI_local *p_local = ABTI_local_get_local(); - ABTI_mutex *p_mutex = ABTI_mutex_get_ptr(mutex); - ABTI_CHECK_NULL_MUTEX_PTR(p_mutex); -- - ABTI_mutex_unlock(p_local, p_mutex); - return ABT_SUCCESS; - } -@@ -422,360 +290,3 @@ int ABT_mutex_equal(ABT_mutex mutex1, ABT_mutex mutex2, ABT_bool *result) - *result = (p_mutex1 == p_mutex2) ? ABT_TRUE : ABT_FALSE; - return ABT_SUCCESS; - } -- --/*****************************************************************************/ --/* Private APIs */ --/*****************************************************************************/ -- --void ABTI_mutex_wait(ABTI_xstream **pp_local_xstream, ABTI_mutex *p_mutex, -- int val) --{ -- ABTI_xstream *p_local_xstream = *pp_local_xstream; -- ABTI_ythread_htable *p_htable = p_mutex->p_htable; -- ABTI_ythread *p_self = ABTI_thread_get_ythread(p_local_xstream->p_thread); -- -- int rank = (int)p_local_xstream->rank; -- ABTI_ASSERT(rank < p_htable->num_rows); -- ABTI_ythread_queue *p_queue = &p_htable->queue[rank]; -- -- ABTI_THREAD_HTABLE_LOCK(p_htable->mutex); -- -- if (ABTD_atomic_acquire_load_uint32(&p_mutex->val) != val) { -- ABTI_THREAD_HTABLE_UNLOCK(p_htable->mutex); -- return; -- } -- -- if (p_queue->p_h_next == NULL) { -- ABTI_ythread_htable_add_h_node(p_htable, p_queue); -- } -- -- /* Change the ULT's state to BLOCKED */ -- ABTI_ythread_set_blocked(p_self); -- -- /* Push the current ULT to the queue */ -- ABTI_ythread_htable_push(p_htable, rank, p_self); -- -- /* Unlock */ -- ABTI_THREAD_HTABLE_UNLOCK(p_htable->mutex); -- -- /* Suspend the current ULT */ -- ABTI_ythread_suspend(pp_local_xstream, p_self, ABT_SYNC_EVENT_TYPE_MUTEX, -- (void *)p_mutex); --} -- --void ABTI_mutex_wait_low(ABTI_xstream **pp_local_xstream, ABTI_mutex *p_mutex, -- int val) --{ -- ABTI_xstream *p_local_xstream = *pp_local_xstream; -- ABTI_ythread_htable *p_htable = p_mutex->p_htable; -- ABTI_ythread *p_self = ABTI_thread_get_ythread(p_local_xstream->p_thread); -- -- int rank = (int)p_local_xstream->rank; -- ABTI_ASSERT(rank < p_htable->num_rows); -- ABTI_ythread_queue *p_queue = &p_htable->queue[rank]; -- -- ABTI_THREAD_HTABLE_LOCK(p_htable->mutex); -- -- if (ABTD_atomic_acquire_load_uint32(&p_mutex->val) != val) { -- ABTI_THREAD_HTABLE_UNLOCK(p_htable->mutex); -- return; -- } -- -- if (p_queue->p_l_next == NULL) { -- ABTI_ythread_htable_add_l_node(p_htable, p_queue); -- } -- -- /* Change the ULT's state to BLOCKED */ -- ABTI_ythread_set_blocked(p_self); -- -- /* Push the current ULT to the queue */ -- ABTI_ythread_htable_push_low(p_htable, rank, p_self); -- -- /* Unlock */ -- ABTI_THREAD_HTABLE_UNLOCK(p_htable->mutex); -- -- /* Suspend the current ULT */ -- ABTI_ythread_suspend(pp_local_xstream, p_self, ABT_SYNC_EVENT_TYPE_MUTEX, -- (void *)p_mutex); --} -- --void ABTI_mutex_wake_de(ABTI_local *p_local, ABTI_mutex *p_mutex) --{ -- int n; -- ABTI_ythread *p_ythread; -- ABTI_ythread_htable *p_htable = p_mutex->p_htable; -- int num = p_mutex->attr.max_wakeups; -- ABTI_ythread_queue *p_start, *p_curr; -- -- /* Wake up num ULTs in a round-robin manner */ -- for (n = 0; n < num; n++) { -- p_ythread = NULL; -- -- ABTI_THREAD_HTABLE_LOCK(p_htable->mutex); -- -- if (ABTD_atomic_acquire_load_uint32(&p_htable->num_elems) == 0) { -- ABTI_THREAD_HTABLE_UNLOCK(p_htable->mutex); -- break; -- } -- -- /* Wake up the high-priority ULTs */ -- p_start = p_htable->h_list; -- for (p_curr = p_start; p_curr;) { -- p_ythread = ABTI_ythread_htable_pop(p_htable, p_curr); -- if (p_curr->num_threads == 0) { -- ABTI_ythread_htable_del_h_head(p_htable); -- } else { -- p_htable->h_list = p_curr->p_h_next; -- } -- if (p_ythread != NULL) -- goto done; -- p_curr = p_htable->h_list; -- if (p_curr == p_start) -- break; -- } -- -- /* Wake up the low-priority ULTs */ -- p_start = p_htable->l_list; -- for (p_curr = p_start; p_curr;) { -- p_ythread = ABTI_ythread_htable_pop_low(p_htable, p_curr); -- if (p_curr->low_num_threads == 0) { -- ABTI_ythread_htable_del_l_head(p_htable); -- } else { -- p_htable->l_list = p_curr->p_l_next; -- } -- if (p_ythread != NULL) -- goto done; -- p_curr = p_htable->l_list; -- if (p_curr == p_start) -- break; -- } -- -- /* Nothing to wake up */ -- ABTI_THREAD_HTABLE_UNLOCK(p_htable->mutex); -- LOG_DEBUG("%p: nothing to wake up\n", p_mutex); -- break; -- -- done: -- ABTI_THREAD_HTABLE_UNLOCK(p_htable->mutex); -- -- /* Push p_ythread to the scheduler's pool */ -- LOG_DEBUG("%p: wake up U%" PRIu64 ":E%d\n", p_mutex, -- ABTI_thread_get_id(&p_ythread->thread), -- p_ythread->thread.p_last_xstream -- ? p_ythread->thread.p_last_xstream->rank -- : -1); -- ABTI_ythread_set_ready(p_local, p_ythread); -- } --} -- --/*****************************************************************************/ --/* Internal static functions */ --/*****************************************************************************/ -- --static inline void mutex_lock_low(ABTI_local **pp_local, ABTI_mutex *p_mutex) --{ -- ABTI_ythread *p_ythread = NULL; -- ABTI_xstream *p_local_xstream = ABTI_local_get_xstream_or_null(*pp_local); -- if (!ABTI_IS_EXT_THREAD_ENABLED || p_local_xstream) { -- p_ythread = ABTI_thread_get_ythread_or_null(p_local_xstream->p_thread); -- } --#ifdef ABT_CONFIG_USE_SIMPLE_MUTEX -- if (p_ythread) { -- LOG_DEBUG("%p: lock_low - try\n", p_mutex); -- while (!ABTD_atomic_bool_cas_strong_uint32(&p_mutex->val, 0, 1)) { -- ABTI_ythread_yield(&p_local_xstream, p_ythread, -- ABT_SYNC_EVENT_TYPE_MUTEX, (void *)p_mutex); -- *pp_local = ABTI_xstream_get_local(p_local_xstream); -- } -- LOG_DEBUG("%p: lock_low - acquired\n", p_mutex); -- } else { -- ABTI_mutex_spinlock(p_mutex); -- } --#else -- /* Only ULTs can yield when the mutex has been locked. For others, -- * just call mutex_spinlock. */ -- if (p_ythread) { -- int c; -- LOG_DEBUG("%p: lock_low - try\n", p_mutex); -- /* If other ULTs associated with the same ES are waiting on the -- * low-mutex queue, we give the header ULT a chance to try to get -- * the mutex by context switching to it. */ -- ABTI_ythread_htable *p_htable = p_mutex->p_htable; -- ABTI_ythread_queue *p_queue = &p_htable->queue[p_local_xstream->rank]; -- if (p_queue->low_num_threads > 0) { -- ABT_bool ret = -- ABTI_ythread_htable_switch_low(&p_local_xstream, p_queue, -- p_ythread, p_htable, -- ABT_SYNC_EVENT_TYPE_MUTEX, -- (void *)p_mutex); -- *pp_local = ABTI_xstream_get_local(p_local_xstream); -- if (ret == ABT_TRUE) { -- /* This ULT became a waiter in the mutex queue */ -- goto check_handover; -- } -- } -- -- if ((c = ABTD_atomic_val_cas_strong_uint32(&p_mutex->val, 0, 1)) != 0) { -- if (c != 2) { -- c = ABTD_atomic_exchange_uint32(&p_mutex->val, 2); -- } -- while (c != 0) { -- ABTI_mutex_wait_low(&p_local_xstream, p_mutex, 2); -- *pp_local = ABTI_xstream_get_local(p_local_xstream); -- -- check_handover: -- /* If the mutex has been handed over to the current ULT from -- * other ULT on the same ES, we don't need to change the mutex -- * state. */ -- if (p_mutex->p_handover) { -- if (p_ythread == p_mutex->p_handover) { -- p_mutex->p_handover = NULL; -- ABTD_atomic_release_store_uint32(&p_mutex->val, 2); -- -- /* Push the previous ULT to its pool */ -- ABTI_ythread *p_giver = p_mutex->p_giver; -- ABTD_atomic_release_store_int(&p_giver->thread.state, -- ABT_THREAD_STATE_READY); -- ABTI_pool_push(p_giver->thread.p_pool, -- p_giver->thread.unit); -- break; -- } -- } -- -- c = ABTD_atomic_exchange_uint32(&p_mutex->val, 2); -- } -- } -- LOG_DEBUG("%p: lock_low - acquired\n", p_mutex); -- } else { -- ABTI_mutex_spinlock(p_mutex); -- } -- -- return; --#endif --} -- --/* Hand over the mutex to other ULT on the same ES */ --static inline void mutex_unlock_se(ABTI_local **pp_local, ABTI_mutex *p_mutex) --{ -- ABTI_ythread *p_ythread = NULL; -- ABTI_xstream *p_local_xstream = ABTI_local_get_xstream_or_null(*pp_local); -- if (!ABTI_IS_EXT_THREAD_ENABLED || p_local_xstream) { -- p_ythread = ABTI_thread_get_ythread_or_null(p_local_xstream->p_thread); -- } --#ifdef ABT_CONFIG_USE_SIMPLE_MUTEX -- ABTD_atomic_release_store_uint32(&p_mutex->val, 0); -- LOG_DEBUG("%p: unlock_se\n", p_mutex); -- if (p_ythread) { -- ABTI_ythread_yield(&p_local_xstream, p_ythread, -- ABT_SYNC_EVENT_TYPE_MUTEX, (void *)p_mutex); -- *pp_local = ABTI_xstream_get_local(p_local_xstream); -- } --#else -- /* If it is run on a non-yieldable thread. just unlock it. */ -- if (!p_ythread) { -- ABTD_atomic_release_store_uint32(&p_mutex->val, 0); /* Unlock */ -- LOG_DEBUG("%p: unlock_se\n", p_mutex); -- ABTI_mutex_wake_de(*pp_local, p_mutex); -- return; -- } -- -- /* Unlock the mutex */ -- /* If p_mutex->val is 1 before decreasing it, it means there is no any -- * waiter in the mutex queue. We can just return. */ -- if (ABTD_atomic_fetch_sub_uint32(&p_mutex->val, 1) == 1) { -- LOG_DEBUG("%p: unlock_se\n", p_mutex); -- if (p_ythread) { -- ABTI_ythread_yield(&p_local_xstream, p_ythread, -- ABT_SYNC_EVENT_TYPE_MUTEX, (void *)p_mutex); -- *pp_local = ABTI_xstream_get_local(p_local_xstream); -- } -- return; -- } -- -- /* There are ULTs waiting in the mutex queue */ -- ABTI_ythread_htable *p_htable = p_mutex->p_htable; -- ABTI_ythread *p_next = NULL; -- ABTI_ythread_queue *p_queue = &p_htable->queue[(int)p_local_xstream->rank]; -- --check_cond: -- /* Check whether the mutex handover is possible */ -- if (p_queue->num_handovers >= p_mutex->attr.max_handovers) { -- ABTD_atomic_release_store_uint32(&p_mutex->val, 0); /* Unlock */ -- LOG_DEBUG("%p: unlock_se\n", p_mutex); -- ABTI_mutex_wake_de(*pp_local, p_mutex); -- p_queue->num_handovers = 0; -- ABTI_ythread_yield(&p_local_xstream, p_ythread, -- ABT_SYNC_EVENT_TYPE_MUTEX, (void *)p_mutex); -- *pp_local = ABTI_xstream_get_local(p_local_xstream); -- return; -- } -- -- /* Hand over the mutex to high-priority ULTs */ -- if (p_queue->num_threads <= 1) { -- if (p_htable->h_list != NULL) { -- ABTD_atomic_release_store_uint32(&p_mutex->val, 0); /* Unlock */ -- LOG_DEBUG("%p: unlock_se\n", p_mutex); -- ABTI_mutex_wake_de(*pp_local, p_mutex); -- ABTI_ythread_yield(&p_local_xstream, p_ythread, -- ABT_SYNC_EVENT_TYPE_MUTEX, (void *)p_mutex); -- *pp_local = ABTI_xstream_get_local(p_local_xstream); -- return; -- } -- } else { -- p_next = ABTI_ythread_htable_pop(p_htable, p_queue); -- if (p_next == NULL) -- goto check_cond; -- else -- goto handover; -- } -- -- /* When we don't have high-priority ULTs and other ESs don't either, -- * we hand over the mutex to low-priority ULTs. */ -- if (p_queue->low_num_threads <= 1) { -- ABTD_atomic_release_store_uint32(&p_mutex->val, 0); /* Unlock */ -- LOG_DEBUG("%p: unlock_se\n", p_mutex); -- ABTI_mutex_wake_de(*pp_local, p_mutex); -- ABTI_ythread_yield(&p_local_xstream, p_ythread, -- ABT_SYNC_EVENT_TYPE_MUTEX, (void *)p_mutex); -- *pp_local = ABTI_xstream_get_local(p_local_xstream); -- return; -- } else { -- p_next = ABTI_ythread_htable_pop_low(p_htable, p_queue); -- if (p_next == NULL) -- goto check_cond; -- } -- --handover: -- /* We don't push p_ythread to the pool. Instead, we will yield_to p_ythread -- * directly at the end of this function. */ -- p_queue->num_handovers++; -- -- /* We are handing over the mutex */ -- p_mutex->p_handover = p_next; -- p_mutex->p_giver = p_ythread; -- -- LOG_DEBUG("%p: handover -> U%" PRIu64 "\n", p_mutex, -- ABTI_thread_get_id(&p_next->thread)); -- -- /* yield_to the next ULT */ -- while (ABTD_atomic_acquire_load_uint32(&p_next->thread.request) & -- ABTI_THREAD_REQ_BLOCK) -- ; -- ABTI_pool_dec_num_blocked(p_next->thread.p_pool); -- ABTD_atomic_release_store_int(&p_next->thread.state, -- ABT_THREAD_STATE_RUNNING); -- ABTI_tool_event_ythread_resume(ABTI_xstream_get_local(p_local_xstream), -- p_next, &p_ythread->thread); -- /* This works as a "yield" for this thread. */ -- ABTI_tool_event_ythread_yield(p_local_xstream, p_ythread, -- p_ythread->thread.p_parent, -- ABT_SYNC_EVENT_TYPE_MUTEX, (void *)p_mutex); -- ABTI_ythread *p_prev = -- ABTI_ythread_context_switch_to_sibling(&p_local_xstream, p_ythread, -- p_next); -- /* Invoke an event of thread resume and run. */ -- *pp_local = ABTI_xstream_get_local(p_local_xstream); -- ABTI_tool_event_thread_run(p_local_xstream, &p_ythread->thread, -- &p_prev->thread, p_ythread->thread.p_parent); --#endif --} -diff --git a/src/mutex_attr.c b/src/mutex_attr.c -index a7c4abf..3793034 100644 ---- a/src/mutex_attr.c -+++ b/src/mutex_attr.c -@@ -34,8 +34,6 @@ int ABT_mutex_attr_create(ABT_mutex_attr *newattr) - p_newattr->attrs = ABTI_MUTEX_ATTR_NONE; - p_newattr->nesting_cnt = 0; - p_newattr->owner_id = 0; -- p_newattr->max_handovers = gp_ABTI_global->mutex_max_handovers; -- p_newattr->max_wakeups = gp_ABTI_global->mutex_max_wakeups; - - /* Return value */ - *newattr = ABTI_mutex_attr_get_handle(p_newattr); -diff --git a/src/rwlock.c b/src/rwlock.c -index 1fab1c1..e606748 100644 ---- a/src/rwlock.c -+++ b/src/rwlock.c -@@ -23,18 +23,13 @@ - */ - int ABT_rwlock_create(ABT_rwlock *newrwlock) - { -- int abt_errno; - ABTI_rwlock *p_newrwlock; - -- abt_errno = ABTU_malloc(sizeof(ABTI_rwlock), (void **)&p_newrwlock); -+ int abt_errno = ABTU_malloc(sizeof(ABTI_rwlock), (void **)&p_newrwlock); - ABTI_CHECK_ERROR(abt_errno); - - ABTI_CHECK_TRUE(p_newrwlock != NULL, ABT_ERR_MEM); -- abt_errno = ABTI_mutex_init(&p_newrwlock->mutex); -- if (ABTI_IS_ERROR_CHECK_ENABLED && abt_errno != ABT_SUCCESS) { -- ABTU_free(p_newrwlock); -- ABTI_HANDLE_ERROR(abt_errno); -- } -+ ABTI_mutex_init(&p_newrwlock->mutex); - ABTI_cond_init(&p_newrwlock->cond); - p_newrwlock->reader_count = 0; - p_newrwlock->write_flag = 0; -@@ -65,7 +60,6 @@ int ABT_rwlock_free(ABT_rwlock *rwlock) - ABTI_rwlock *p_rwlock = ABTI_rwlock_get_ptr(h_rwlock); - ABTI_CHECK_NULL_RWLOCK_PTR(p_rwlock); - -- ABTI_mutex_fini(&p_rwlock->mutex); - ABTI_cond_fini(&p_rwlock->cond); - ABTU_free(p_rwlock); - -diff --git a/src/sched/sched.c b/src/sched/sched.c -index 3bfc436..5686cb7 100644 ---- a/src/sched/sched.c -+++ b/src/sched/sched.c -@@ -166,7 +166,8 @@ int ABT_sched_get_pools(ABT_sched sched, int max_pools, int idx, - { - ABTI_sched *p_sched = ABTI_sched_get_ptr(sched); - ABTI_CHECK_NULL_SCHED_PTR(p_sched); -- ABTI_CHECK_TRUE(idx + max_pools <= p_sched->num_pools, ABT_ERR_SCHED); -+ ABTI_CHECK_TRUE((size_t)(idx + max_pools) <= p_sched->num_pools, -+ ABT_ERR_SCHED); - - int p; - for (p = idx; p < idx + max_pools; p++) { -@@ -306,8 +307,7 @@ int ABT_sched_get_size(ABT_sched sched, size_t *size) - - size_t ABTI_sched_get_size(ABTI_sched *p_sched) - { -- size_t pool_size = 0; -- int p; -+ size_t pool_size = 0, p; - - for (p = 0; p < p_sched->num_pools; p++) { - ABTI_pool *p_pool = ABTI_pool_get_ptr(p_sched->pools[p]); -@@ -500,7 +500,7 @@ void ABTI_sched_free(ABTI_local *p_local, ABTI_sched *p_sched, - ABTI_ASSERT(p_sched->used == ABTI_SCHED_NOT_USED); - /* If sched is a default provided one, it should free its pool here. - * Otherwise, freeing the pool is the user's responsibility. */ -- int p; -+ size_t p; - for (p = 0; p < p_sched->num_pools; p++) { - ABTI_pool *p_pool = ABTI_pool_get_ptr(p_sched->pools[p]); - int32_t num_scheds = ABTI_pool_release(p_pool); -@@ -585,8 +585,7 @@ ABTU_ret_err int ABTI_sched_get_migration_pool(ABTI_sched *p_sched, - - size_t ABTI_sched_get_total_size(ABTI_sched *p_sched) - { -- size_t pool_size = 0; -- int p; -+ size_t pool_size = 0, p; - - for (p = 0; p < p_sched->num_pools; p++) { - ABTI_pool *p_pool = ABTI_pool_get_ptr(p_sched->pools[p]); -@@ -603,8 +602,7 @@ size_t ABTI_sched_get_total_size(ABTI_sched *p_sched) - * between different schedulers associated with different ESs. */ - size_t ABTI_sched_get_effective_size(ABTI_local *p_local, ABTI_sched *p_sched) - { -- size_t pool_size = 0; -- int p; -+ size_t pool_size = 0, p; - - for (p = 0; p < p_sched->num_pools; p++) { - ABT_pool pool = p_sched->pools[p]; -@@ -649,6 +647,8 @@ void ABTI_sched_print(ABTI_sched *p_sched, FILE *p_os, int indent, - kind_str = "BASIC_WAIT"; - } else if (kind == sched_get_kind(ABTI_sched_get_prio_def())) { - kind_str = "PRIO"; -+ } else if (kind == sched_get_kind(ABTI_sched_get_randws_def())) { -+ kind_str = "RANDWS"; - } else { - kind_str = "USER"; - } -@@ -689,9 +689,10 @@ void ABTI_sched_print(ABTI_sched *p_sched, FILE *p_os, int indent, - "%*sused : %s\n" - "%*sautomatic: %s\n" - "%*srequest : 0x%x\n" -- "%*snum_pools: %d\n" -+ "%*snum_pools: %zu\n" - "%*ssize : %zu\n" - "%*stot_size : %zu\n" -+ "%*sthread : %p\n" - "%*sdata : %p\n", - indent, "", (void *)p_sched, - #ifdef ABT_CONFIG_USE_DEBUG_LOG -@@ -703,9 +704,9 @@ void ABTI_sched_print(ABTI_sched *p_sched, FILE *p_os, int indent, - ABTD_atomic_acquire_load_uint32(&p_sched->request), indent, "", - p_sched->num_pools, indent, "", ABTI_sched_get_size(p_sched), - indent, "", ABTI_sched_get_total_size(p_sched), indent, "", -- p_sched->data); -+ (void *)p_sched->p_ythread, indent, "", p_sched->data); - if (print_sub == ABT_TRUE) { -- int i; -+ size_t i; - for (i = 0; i < p_sched->num_pools; i++) { - ABTI_pool *p_pool = ABTI_pool_get_ptr(p_sched->pools[i]); - ABTI_pool_print(p_pool, p_os, indent + 2); -diff --git a/src/stream.c b/src/stream.c -index b0ac0eb..9968fb4 100644 ---- a/src/stream.c -+++ b/src/stream.c -@@ -570,7 +570,7 @@ int ABT_xstream_get_main_pools(ABT_xstream xstream, int max_pools, - ABTI_CHECK_NULL_XSTREAM_PTR(p_xstream); - - ABTI_sched *p_sched = p_xstream->p_main_sched; -- max_pools = p_sched->num_pools > max_pools ? max_pools : p_sched->num_pools; -+ max_pools = ABTU_min_int(p_sched->num_pools, max_pools); - memcpy(pools, p_sched->pools, sizeof(ABT_pool) * max_pools); - return ABT_SUCCESS; - } -@@ -839,7 +839,7 @@ int ABT_xstream_get_affinity(ABT_xstream xstream, int cpuset_size, int *cpuset, - ABTI_CHECK_ERROR(abt_errno); - - int i, n; -- n = affinity.num_cpuids > cpuset_size ? cpuset_size : affinity.num_cpuids; -+ n = ABTU_min_int(affinity.num_cpuids, cpuset_size); - *num_cpus = n; - for (i = 0; i < n; i++) { - cpuset[i] = affinity.cpuids[i]; -@@ -1003,18 +1003,26 @@ void ABTI_xstream_print(ABTI_xstream *p_xstream, FILE *p_os, int indent, - - fprintf(p_os, - "%*s== ES (%p) ==\n" -- "%*srank : %d\n" -- "%*stype : %s\n" -- "%*sstate : %s\n" -- "%*smain_sched: %p\n", -+ "%*srank : %d\n" -+ "%*stype : %s\n" -+ "%*sstate : %s\n" -+ "%*sroot_ythread : %p\n" -+ "%*sroot_pool : %p\n" -+ "%*sthread : %p\n" -+ "%*smain_sched : %p\n", - indent, "", (void *)p_xstream, indent, "", p_xstream->rank, - indent, "", type, indent, "", state, indent, "", -+ (void *)p_xstream->p_root_ythread, indent, "", -+ (void *)p_xstream->p_root_pool, indent, "", -+ (void *)p_xstream->p_thread, indent, "", - (void *)p_xstream->p_main_sched); - - if (print_sub == ABT_TRUE) { - ABTI_sched_print(p_xstream->p_main_sched, p_os, - indent + ABTI_INDENT, ABT_TRUE); - } -+ fprintf(p_os, "%*sctx :\n", indent, ""); -+ ABTD_xstream_context_print(&p_xstream->ctx, p_os, indent + ABTI_INDENT); - } - fflush(p_os); - } -@@ -1361,7 +1369,7 @@ xstream_update_main_sched(ABTI_xstream **pp_local_xstream, - ABTI_ythread *p_ythread = NULL; - ABTI_sched *p_main_sched; - ABTI_pool *p_tar_pool = NULL; -- int p; -+ size_t p; - - /* The main scheduler will to be a ULT, not a tasklet */ - p_sched->type = ABT_SCHED_TYPE_ULT; -diff --git a/src/stream_barrier.c b/src/stream_barrier.c -index bc35a47..051e2ca 100644 ---- a/src/stream_barrier.c -+++ b/src/stream_barrier.c -@@ -26,7 +26,6 @@ - int ABT_xstream_barrier_create(uint32_t num_waiters, - ABT_xstream_barrier *newbarrier) - { --#ifdef HAVE_PTHREAD_BARRIER_INIT - int abt_errno; - ABTI_xstream_barrier *p_newbarrier; - -@@ -35,18 +34,21 @@ int ABT_xstream_barrier_create(uint32_t num_waiters, - ABTI_CHECK_ERROR(abt_errno); - - p_newbarrier->num_waiters = num_waiters; -+#ifdef HAVE_PTHREAD_BARRIER_INIT - abt_errno = ABTD_xstream_barrier_init(num_waiters, &p_newbarrier->bar); - if (ABTI_IS_ERROR_CHECK_ENABLED && abt_errno != ABT_SUCCESS) { - ABTU_free(p_newbarrier); - ABTI_HANDLE_ERROR(abt_errno); - } -+#else -+ ABTI_spinlock_clear(&p_newbarrier->lock); -+ p_newbarrier->counter = 0; -+ ABTD_atomic_relaxed_store_uint64(&p_newbarrier->tag, 0); -+#endif - - /* Return value */ - *newbarrier = ABTI_xstream_barrier_get_handle(p_newbarrier); - return ABT_SUCCESS; --#else -- ABTI_HANDLE_ERROR(ABT_ERR_FEATURE_NA); --#endif - } - - /** -@@ -63,20 +65,18 @@ int ABT_xstream_barrier_create(uint32_t num_waiters, - */ - int ABT_xstream_barrier_free(ABT_xstream_barrier *barrier) - { --#ifdef HAVE_PTHREAD_BARRIER_INIT - ABT_xstream_barrier h_barrier = *barrier; - ABTI_xstream_barrier *p_barrier = ABTI_xstream_barrier_get_ptr(h_barrier); - ABTI_CHECK_NULL_XSTREAM_BARRIER_PTR(p_barrier); - -+#ifdef HAVE_PTHREAD_BARRIER_INIT - ABTD_xstream_barrier_destroy(&p_barrier->bar); -+#endif - ABTU_free(p_barrier); - - /* Return value */ - *barrier = ABT_XSTREAM_BARRIER_NULL; - return ABT_SUCCESS; --#else -- ABTI_HANDLE_ERROR(ABT_ERR_FEATURE_NA); --#endif - } - - /** -@@ -92,15 +92,35 @@ int ABT_xstream_barrier_free(ABT_xstream_barrier *barrier) - */ - int ABT_xstream_barrier_wait(ABT_xstream_barrier barrier) - { --#ifdef HAVE_PTHREAD_BARRIER_INIT - ABTI_xstream_barrier *p_barrier = ABTI_xstream_barrier_get_ptr(barrier); - ABTI_CHECK_NULL_XSTREAM_BARRIER_PTR(p_barrier); - - if (p_barrier->num_waiters > 1) { -+#ifdef HAVE_PTHREAD_BARRIER_INIT - ABTD_xstream_barrier_wait(&p_barrier->bar); -- } -- return ABT_SUCCESS; - #else -- ABTI_HANDLE_ERROR(ABT_ERR_FEATURE_NA); -+ /* The following implementation is a simple sense-reversal barrier -+ * implementation while it uses uint64_t instead of boolean to prevent -+ * a sense variable from wrapping around. */ -+ ABTI_spinlock_acquire(&p_barrier->lock); -+ p_barrier->counter++; -+ if (p_barrier->counter == p_barrier->num_waiters) { -+ /* Wake up the other waiters. */ -+ p_barrier->counter = 0; -+ /* Updating tag wakes up other waiters. Note that this tag is -+ * sufficiently large, so it will not wrap around. */ -+ uint64_t cur_tag = ABTD_atomic_relaxed_load_uint64(&p_barrier->tag); -+ uint64_t new_tag = (cur_tag + 1) & (UINT64_MAX >> 1); -+ ABTD_atomic_release_store_uint64(&p_barrier->tag, new_tag); -+ ABTI_spinlock_release(&p_barrier->lock); -+ } else { -+ /* Wait until the tag is updated by the last waiter */ -+ uint64_t cur_tag = ABTD_atomic_relaxed_load_uint64(&p_barrier->tag); -+ ABTI_spinlock_release(&p_barrier->lock); -+ while (cur_tag == ABTD_atomic_acquire_load_uint64(&p_barrier->tag)) -+ ABTD_atomic_pause(); -+ } - #endif -+ } -+ return ABT_SUCCESS; - } -diff --git a/src/thread.c b/src/thread.c -index e60a044..69a98b9 100644 ---- a/src/thread.c -+++ b/src/thread.c -@@ -1536,12 +1536,14 @@ void ABTI_thread_print(ABTI_thread *p_thread, FILE *p_os, int indent) - } else { - ABTI_xstream *p_xstream = p_thread->p_last_xstream; - int xstream_rank = p_xstream ? p_xstream->rank : 0; -- const char *type, *yieldable, *state; -+ const char *type, *yieldable, *state, *named, *migratable; - - if (p_thread->type & ABTI_THREAD_TYPE_MAIN) { - type = "MAIN"; - } else if (p_thread->type & ABTI_THREAD_TYPE_MAIN_SCHED) { - type = "MAIN_SCHED"; -+ } else if (p_thread->type & ABTI_THREAD_TYPE_ROOT) { -+ type = "ROOT"; - } else { - type = "USER"; - } -@@ -1550,6 +1552,16 @@ void ABTI_thread_print(ABTI_thread *p_thread, FILE *p_os, int indent) - } else { - yieldable = "no"; - } -+ if (p_thread->type & ABTI_THREAD_TYPE_NAMED) { -+ named = "yes"; -+ } else { -+ named = "no"; -+ } -+ if (p_thread->type & ABTI_THREAD_TYPE_MIGRATABLE) { -+ migratable = "yes"; -+ } else { -+ migratable = "no"; -+ } - switch (ABTD_atomic_acquire_load_int(&p_thread->state)) { - case ABT_THREAD_STATE_READY: - state = "READY"; -@@ -1567,25 +1579,45 @@ void ABTI_thread_print(ABTI_thread *p_thread, FILE *p_os, int indent) - state = "UNKNOWN"; - break; - } -+ ABTI_thread_mig_data *p_mig_data = -+ (ABTI_thread_mig_data *)ABTI_ktable_get(&p_thread->p_keytable, -+ &g_thread_mig_data_key); -+ void *p_migration_cb_arg = -+ p_mig_data ? p_mig_data->p_migration_cb_arg : NULL; - - fprintf(p_os, - "%*s== Thread (%p) ==\n" -- "%*sid : %" PRIu64 "\n" -- "%*stype : %s\n" -- "%*syieldable : %s\n" -- "%*sstate : %s\n" -- "%*slast_ES : %p (%d)\n" -- "%*sp_arg : %p\n" -- "%*spool : %p\n" -- "%*srequest : 0x%x\n" -- "%*skeytable : %p\n", -+ "%*sid : %" PRIu64 "\n" -+ "%*stype : %s\n" -+ "%*syieldable : %s\n" -+ "%*sstate : %s\n" -+ "%*slast_ES : %p (%d)\n" -+ "%*sparent : %p\n" -+ "%*sp_arg : %p\n" -+ "%*spool : %p\n" -+ "%*snamed : %s\n" -+ "%*smigratable : %s\n" -+ "%*srequest : 0x%x\n" -+ "%*smig_cb_arg : %p\n" -+ "%*skeytable : %p\n", - indent, "", (void *)p_thread, indent, "", - ABTI_thread_get_id(p_thread), indent, "", type, indent, "", - yieldable, indent, "", state, indent, "", (void *)p_xstream, -- xstream_rank, indent, "", p_thread->p_arg, indent, "", -- (void *)p_thread->p_pool, indent, "", -+ xstream_rank, indent, "", (void *)p_thread->p_parent, indent, -+ "", p_thread->p_arg, indent, "", (void *)p_thread->p_pool, -+ indent, "", named, indent, "", migratable, indent, "", - ABTD_atomic_acquire_load_uint32(&p_thread->request), indent, "", -+ p_migration_cb_arg, indent, "", - ABTD_atomic_acquire_load_ptr(&p_thread->p_keytable)); -+ -+ if (p_thread->type & ABTI_THREAD_TYPE_YIELDABLE) { -+ ABTI_ythread *p_ythread = ABTI_thread_get_ythread(p_thread); -+ fprintf(p_os, -+ "%*sstack : %p\n" -+ "%*sstacksize : %zu\n", -+ indent, "", p_ythread->p_stack, indent, "", -+ p_ythread->stacksize); -+ } - } - fflush(p_os); - } -diff --git a/src/thread_attr.c b/src/thread_attr.c -index cf2d7d0..6320864 100644 ---- a/src/thread_attr.c -+++ b/src/thread_attr.c -@@ -5,6 +5,9 @@ - - #include "abti.h" - -+static void thread_attr_set_stack(ABTI_thread_attr *p_attr, void *stackaddr, -+ size_t stacksize); -+ - /** @defgroup ULT_ATTR ULT Attributes - * Attributes are used to specify ULT behavior that is different from the - * default. When a ULT is created with \c ABT_thread_create(), attributes -@@ -86,26 +89,10 @@ int ABT_thread_attr_set_stack(ABT_thread_attr attr, void *stackaddr, - { - ABTI_thread_attr *p_attr = ABTI_thread_attr_get_ptr(attr); - ABTI_CHECK_NULL_THREAD_ATTR_PTR(p_attr); -- -- ABTI_thread_type new_thread_type; -- if (stackaddr != NULL) { -- if (((uintptr_t)stackaddr & 0x7) != 0) { -- ABTI_HANDLE_ERROR(ABT_ERR_OTHER); -- } -- new_thread_type = ABTI_THREAD_TYPE_MEM_MEMPOOL_DESC; -- } else { -- if (stacksize == gp_ABTI_global->thread_stacksize) { -- new_thread_type = ABTI_THREAD_TYPE_MEM_MEMPOOL_DESC_STACK; -- } else { -- new_thread_type = ABTI_THREAD_TYPE_MEM_MALLOC_DESC_STACK; -- } -- } -- /* Unset the stack type and set new_thread_type. */ -- p_attr->thread_type &= ~ABTI_THREAD_TYPES_MEM; -- p_attr->thread_type |= new_thread_type; -- -- p_attr->p_stack = stackaddr; -- p_attr->stacksize = stacksize; -+ /* If stackaddr is not NULL, it must be aligned by 8 bytes. */ -+ ABTI_CHECK_TRUE(stackaddr == NULL || ((uintptr_t)stackaddr & 0x7) == 0, -+ ABT_ERR_OTHER); -+ thread_attr_set_stack(p_attr, stackaddr, stacksize); - return ABT_SUCCESS; - } - -@@ -152,18 +139,7 @@ int ABT_thread_attr_set_stacksize(ABT_thread_attr attr, size_t stacksize) - { - ABTI_thread_attr *p_attr = ABTI_thread_attr_get_ptr(attr); - ABTI_CHECK_NULL_THREAD_ATTR_PTR(p_attr); -- -- /* Set the value */ -- p_attr->stacksize = stacksize; -- ABTI_thread_type new_thread_type; -- if (stacksize == gp_ABTI_global->thread_stacksize) { -- new_thread_type = ABTI_THREAD_TYPE_MEM_MEMPOOL_DESC_STACK; -- } else { -- new_thread_type = ABTI_THREAD_TYPE_MEM_MEMPOOL_DESC_STACK; -- } -- /* Unset the stack type and set new_thread_type. */ -- p_attr->thread_type &= ~ABTI_THREAD_TYPES_MEM; -- p_attr->thread_type |= new_thread_type; -+ thread_attr_set_stack(p_attr, p_attr->p_stack, stacksize); - return ABT_SUCCESS; - } - -@@ -308,3 +284,38 @@ ABTU_ret_err int ABTI_thread_attr_dup(const ABTI_thread_attr *p_attr, - *pp_dup_attr = p_dup_attr; - return ABT_SUCCESS; - } -+ -+/*****************************************************************************/ -+/* Internal static functions */ -+/*****************************************************************************/ -+ -+static void thread_attr_set_stack(ABTI_thread_attr *p_attr, void *stackaddr, -+ size_t stacksize) -+{ -+ /* Get the best thread type. */ -+ ABTI_thread_type new_thread_type; -+ if (stackaddr != NULL) { -+ /* This check must be done by the caller. */ -+ ABTI_ASSERT(((uintptr_t)stackaddr & 0x7) == 0); -+ /* Only a descriptor will be allocated from a memory pool. A stack -+ * is given by the user. */ -+ new_thread_type = ABTI_THREAD_TYPE_MEM_MEMPOOL_DESC; -+ } else { -+ if (stacksize == gp_ABTI_global->thread_stacksize) { -+ /* Both a stack and a descriptor will be allocated from a memory -+ * pool. */ -+ new_thread_type = ABTI_THREAD_TYPE_MEM_MEMPOOL_DESC_STACK; -+ } else { -+ /* The stack must be allocated by malloc(). Let's allocate both -+ * a stack and a descriptor together by a single malloc(). */ -+ new_thread_type = ABTI_THREAD_TYPE_MEM_MALLOC_DESC_STACK; -+ } -+ } -+ -+ /* Unset the stack type and set new_thread_type. */ -+ p_attr->thread_type &= ~ABTI_THREAD_TYPES_MEM; -+ p_attr->thread_type |= new_thread_type; -+ -+ p_attr->p_stack = stackaddr; -+ p_attr->stacksize = stacksize; -+} -diff --git a/src/util/Makefile.mk b/src/util/Makefile.mk -index 59a86e3..acdde2c 100644 ---- a/src/util/Makefile.mk -+++ b/src/util/Makefile.mk -@@ -4,4 +4,5 @@ - # - - abt_sources += \ -+ util/atoi.c \ - util/largepage.c -diff --git a/src/util/atoi.c b/src/util/atoi.c -new file mode 100644 -index 0000000..65245a0 ---- /dev/null -+++ b/src/util/atoi.c -@@ -0,0 +1,305 @@ -+/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */ -+/* -+ * See COPYRIGHT in top-level directory. -+ */ -+ -+#include "abti.h" -+ -+static ABTU_ret_err int atoi_impl(const char *str, ABT_bool *p_is_signed, -+ uint64_t *p_val, ABT_bool *p_overflow); -+ -+ABTU_ret_err int ABTU_atoi(const char *str, int *p_val, ABT_bool *p_overflow) -+{ -+ uint64_t val; -+ ABT_bool overflow, is_signed; -+ int abt_errno = atoi_impl(str, &is_signed, &val, &overflow); -+ ABTI_CHECK_ERROR(abt_errno); -+ if (is_signed) { -+ if (val > (uint64_t)(-(int64_t)INT_MIN)) { -+ /* Underflow. */ -+ overflow = ABT_TRUE; -+ *p_val = INT_MIN; -+ } else { -+ *p_val = (int)(-(int64_t)val); -+ } -+ } else { -+ if (val > (uint64_t)INT_MAX) { -+ /* Overflow. */ -+ overflow = ABT_TRUE; -+ *p_val = INT_MAX; -+ } else { -+ *p_val = (int)val; -+ } -+ } -+ if (p_overflow) -+ *p_overflow = overflow; -+ return abt_errno; -+} -+ -+ABTU_ret_err int ABTU_atoui32(const char *str, uint32_t *p_val, -+ ABT_bool *p_overflow) -+{ -+ uint64_t val; -+ ABT_bool overflow, is_signed; -+ int abt_errno = atoi_impl(str, &is_signed, &val, &overflow); -+ ABTI_CHECK_ERROR(abt_errno); -+ if (is_signed) { -+ /* Underflow. */ -+ if (val != 0) -+ overflow = ABT_TRUE; -+ *p_val = 0; -+ } else { -+ if (val > (uint64_t)UINT32_MAX) { -+ /* Overflow. */ -+ overflow = ABT_TRUE; -+ *p_val = UINT32_MAX; -+ } else { -+ *p_val = (uint32_t)val; -+ } -+ } -+ if (p_overflow) -+ *p_overflow = overflow; -+ return abt_errno; -+} -+ -+ABTU_ret_err int ABTU_atoui64(const char *str, uint64_t *p_val, -+ ABT_bool *p_overflow) -+{ -+ uint64_t val; -+ ABT_bool overflow, is_signed; -+ int abt_errno = atoi_impl(str, &is_signed, &val, &overflow); -+ ABTI_CHECK_ERROR(abt_errno); -+ if (is_signed) { -+ /* Underflow. */ -+ if (val != 0) -+ overflow = ABT_TRUE; -+ *p_val = 0; -+ } else { -+ *p_val = val; -+ } -+ if (p_overflow) -+ *p_overflow = overflow; -+ return abt_errno; -+} -+ -+ABTU_ret_err int ABTU_atosz(const char *str, size_t *p_val, -+ ABT_bool *p_overflow) -+{ -+ ABTI_STATIC_ASSERT(sizeof(size_t) == 4 || sizeof(size_t) == 8); -+ if (sizeof(size_t) == 4) { -+ uint32_t val; -+ ABT_bool overflow; -+ int abt_errno = ABTU_atoui32(str, &val, &overflow); -+ ABTI_CHECK_ERROR(abt_errno); -+ *p_val = (size_t)val; -+ if (p_overflow) -+ *p_overflow = overflow; -+ return abt_errno; -+ } else { -+ uint64_t val; -+ ABT_bool overflow; -+ int abt_errno = ABTU_atoui64(str, &val, &overflow); -+ ABTI_CHECK_ERROR(abt_errno); -+ *p_val = (size_t)val; -+ if (p_overflow) -+ *p_overflow = overflow; -+ return abt_errno; -+ } -+} -+ -+/*****************************************************************************/ -+/* Internal static functions */ -+/*****************************************************************************/ -+ -+static ABTU_ret_err int atoi_impl(const char *str, ABT_bool *p_is_signed, -+ uint64_t *p_val, ABT_bool *p_overflow) -+{ -+ uint64_t val = 0; -+ ABT_bool is_signed = ABT_FALSE, read_char = ABT_FALSE, -+ read_digit = ABT_FALSE; -+ while (1) { -+ if ((*str == '\n' || *str == '\t' || *str == ' ' || *str == '\r') && -+ read_char == ABT_FALSE) { -+ /* Do nothing. */ -+ } else if (*str == '+' && read_digit == ABT_FALSE) { -+ read_char = ABT_TRUE; -+ } else if (*str == '-' && read_digit == ABT_FALSE) { -+ /* Flip the digit. */ -+ read_char = ABT_TRUE; -+ is_signed = is_signed ? ABT_FALSE : ABT_TRUE; -+ } else if ('0' <= *str && *str <= '9') { -+ read_char = ABT_TRUE; -+ read_digit = ABT_TRUE; -+ /* Will val overflow? */ -+ if ((val > UINT64_MAX / 10) || -+ (val * 10 > UINT64_MAX - (uint64_t)(*str - '0'))) { -+ /* Overflow. */ -+ *p_overflow = ABT_TRUE; -+ *p_val = UINT64_MAX; -+ *p_is_signed = is_signed; -+ return ABT_SUCCESS; -+ } -+ val = val * 10 + (uint64_t)(*str - '0'); -+ read_digit = ABT_TRUE; -+ } else { -+ /* Stop reading str. */ -+ if (read_digit == ABT_FALSE) { -+ /* No integer. */ -+ return ABT_ERR_INV_ARG; -+ } -+ *p_overflow = ABT_FALSE; -+ *p_val = val; -+ *p_is_signed = is_signed; -+ return ABT_SUCCESS; -+ } -+ str++; -+ } -+} -+ -+#if 0 -+ -+void test_ABTU_atoi(const char *str, int err, int val, ABT_bool overflow) -+{ -+ int ret_val; -+ ABT_bool ret_overflow; -+ int ret_err = ABTU_atoi(str, &ret_val, &ret_overflow); -+ assert(err == ret_err); -+ if (err == ABT_SUCCESS) { -+ assert(val == ret_val); -+ assert(overflow == ret_overflow); -+ } -+} -+ -+void test_ABTU_atoui32(const char *str, int err, uint32_t val, ABT_bool overflow) -+{ -+ uint32_t ret_val; -+ ABT_bool ret_overflow; -+ int ret_err = ABTU_atoui32(str, &ret_val, &ret_overflow); -+ assert(err == ret_err); -+ if (err == ABT_SUCCESS) { -+ assert(val == ret_val); -+ assert(overflow == ret_overflow); -+ } -+} -+ -+void test_ABTU_atoui64(const char *str, int err, uint64_t val, ABT_bool overflow) -+{ -+ uint64_t ret_val; -+ ABT_bool ret_overflow; -+ int ret_err = ABTU_atoui64(str, &ret_val, &ret_overflow); -+ assert(err == ret_err); -+ if (err == ABT_SUCCESS) { -+ assert(val == ret_val); -+ assert(overflow == ret_overflow); -+ } -+} -+ -+void test_ABTU_atosz(const char *str, int err, size_t val, ABT_bool overflow) -+{ -+ size_t ret_val; -+ ABT_bool ret_overflow; -+ int ret_err = ABTU_atosz(str, &ret_val, &ret_overflow); -+ assert(err == ret_err); -+ if (err == ABT_SUCCESS) { -+ assert(val == ret_val); -+ assert(overflow == ret_overflow); -+ } -+} -+ -+int main() -+{ -+ typedef struct { -+ const char *str; -+ int err; -+ int val; -+ } base_case_t; -+ -+ /* Basic cases (no overflow). */ -+ base_case_t cases[] = { -+ { "0", ABT_SUCCESS, 0 }, -+ { "63", ABT_SUCCESS, 63 }, -+ { "+14", ABT_SUCCESS, 14 }, -+ { "+0", ABT_SUCCESS, 0 }, -+ { "+-+-+---++0", ABT_SUCCESS, 0 }, -+ { "+-+-+---+-+8800", ABT_SUCCESS, 8800 }, -+ { "----1---", ABT_SUCCESS, 1 }, -+ { "abc", ABT_ERR_INV_ARG, 0 }, -+ { "13abc", ABT_SUCCESS, 13 }, -+ { "000123456", ABT_SUCCESS, 123456 }, -+ { "00000000", ABT_SUCCESS, 0 }, -+ { "123x456", ABT_SUCCESS, 123 }, -+ { "123+456", ABT_SUCCESS, 123 }, -+ { "123 456", ABT_SUCCESS, 123 }, -+ { "--12-3-45-6", ABT_SUCCESS, 12 }, -+ { "", ABT_ERR_INV_ARG, 0 }, -+ { "+", ABT_ERR_INV_ARG, 0 }, -+ { "-", ABT_ERR_INV_ARG, 0 }, -+ { "+ 2", ABT_ERR_INV_ARG, 0 }, -+ { " \n\t\r+-+-", ABT_ERR_INV_ARG, 0 }, -+ { " \n\t\r+-+-123", ABT_SUCCESS, 123 }, -+ }; -+ -+ size_t i; -+ for (i = 0; i < sizeof(cases) / sizeof(cases[0]); i++) { -+ test_ABTU_atoi(cases[i].str, cases[i].err, cases[i].val, ABT_FALSE); -+ test_ABTU_atoui32(cases[i].str, cases[i].err, cases[i].val, ABT_FALSE); -+ test_ABTU_atoui64(cases[i].str, cases[i].err, cases[i].val, ABT_FALSE); -+ test_ABTU_atosz(cases[i].str, cases[i].err, cases[i].val, ABT_FALSE); -+ } -+ -+ /* Check negative values. */ -+ test_ABTU_atoi("-1", ABT_SUCCESS, -1, ABT_FALSE); -+ test_ABTU_atoi("-9990", ABT_SUCCESS, -9990, ABT_FALSE); -+ test_ABTU_atoi(" --+-1234a-", ABT_SUCCESS, -1234, ABT_FALSE); -+ -+ /* Check overflow/underflow */ -+ test_ABTU_atoi("2147483646", ABT_SUCCESS, 2147483646, ABT_FALSE); -+ test_ABTU_atoi("2147483647", ABT_SUCCESS, 2147483647, ABT_FALSE); -+ test_ABTU_atoi("2147483648", ABT_SUCCESS, 2147483647, ABT_TRUE); -+ test_ABTU_atoi("11112147483648", ABT_SUCCESS, 2147483647, ABT_TRUE); -+ test_ABTU_atoi("-2147483647", ABT_SUCCESS, -2147483647, ABT_FALSE); -+ test_ABTU_atoi("-2147483648", ABT_SUCCESS, -2147483648, ABT_FALSE); -+ test_ABTU_atoi("-2147483649", ABT_SUCCESS, -2147483648, ABT_TRUE); -+ test_ABTU_atoi("-11112147483648", ABT_SUCCESS, -2147483648, ABT_TRUE); -+ -+ test_ABTU_atoui32("4294967294", ABT_SUCCESS, 4294967294, ABT_FALSE); -+ test_ABTU_atoui32("4294967295", ABT_SUCCESS, 4294967295, ABT_FALSE); -+ test_ABTU_atoui32("4294967296", ABT_SUCCESS, 4294967295, ABT_TRUE); -+ test_ABTU_atoui32("11114294967295", ABT_SUCCESS, 4294967295, ABT_TRUE); -+ test_ABTU_atoui32("-1", ABT_SUCCESS, 0, ABT_TRUE); -+ test_ABTU_atoui32("-2147483649", ABT_SUCCESS, 0, ABT_TRUE); -+ -+ test_ABTU_atoui64("18446744073709551614", ABT_SUCCESS, -+ 18446744073709551614u, ABT_FALSE); -+ test_ABTU_atoui64("18446744073709551615", ABT_SUCCESS, -+ 18446744073709551615u, ABT_FALSE); -+ test_ABTU_atoui64("18446744073709551616", ABT_SUCCESS, -+ 18446744073709551615u, ABT_TRUE); -+ test_ABTU_atoui64("111118446744073709551615", ABT_SUCCESS, -+ 18446744073709551615u, ABT_TRUE); -+ test_ABTU_atoui64("-1", ABT_SUCCESS, 0, ABT_TRUE); -+ test_ABTU_atoui64("-18446744073709551616", ABT_SUCCESS, 0, ABT_TRUE); -+ -+ if (sizeof(size_t) == 4) { -+ test_ABTU_atosz("4294967294", ABT_SUCCESS, 4294967294, ABT_FALSE); -+ test_ABTU_atosz("4294967295", ABT_SUCCESS, 4294967295, ABT_FALSE); -+ test_ABTU_atosz("4294967296", ABT_SUCCESS, 4294967295, ABT_TRUE); -+ test_ABTU_atosz("11114294967295", ABT_SUCCESS, 4294967295, ABT_TRUE); -+ test_ABTU_atosz("-1", ABT_SUCCESS, 0, ABT_TRUE); -+ test_ABTU_atosz("-2147483649", ABT_SUCCESS, 0, ABT_TRUE); -+ } else { -+ assert(sizeof(size_t) == 8); -+ test_ABTU_atosz("18446744073709551614", ABT_SUCCESS, -+ 18446744073709551614u, ABT_FALSE); -+ test_ABTU_atosz("18446744073709551615", ABT_SUCCESS, -+ 18446744073709551615u, ABT_FALSE); -+ test_ABTU_atosz("18446744073709551616", ABT_SUCCESS, -+ 18446744073709551615u, ABT_TRUE); -+ test_ABTU_atosz("111118446744073709551615", ABT_SUCCESS, -+ 18446744073709551615u, ABT_TRUE); -+ test_ABTU_atosz("-1", ABT_SUCCESS, 0, ABT_TRUE); -+ test_ABTU_atosz("-18446744073709551616", ABT_SUCCESS, 0, ABT_TRUE); -+ } -+} -+ -+#endif -diff --git a/src/ythread.c b/src/ythread.c -index 02b2c7f..9fdba7d 100644 ---- a/src/ythread.c -+++ b/src/ythread.c -@@ -5,6 +5,21 @@ - - #include "abti.h" - -+#ifdef ABT_CONFIG_ENABLE_STACK_UNWIND -+ -+#ifndef ABT_CONFIG_ENABLE_PEEK_CONTEXT -+#error "ABT_CONFIG_ENABLE_PEEK_CONTEXT must be enabled" -+#endif -+ -+#define UNW_LOCAL_ONLY -+#include -+struct unwind_stack_t { -+ FILE *fp; -+}; -+static void ythread_unwind_stack(void *arg); -+ -+#endif -+ - void ABTI_ythread_set_blocked(ABTI_ythread *p_ythread) - { - /* The root thread cannot be blocked */ -@@ -85,10 +100,33 @@ void ABTI_ythread_set_ready(ABTI_local *p_local, ABTI_ythread *p_ythread) - ABTU_no_sanitize_address void ABTI_ythread_print_stack(ABTI_ythread *p_ythread, - FILE *p_os) - { -+ ABTD_ythread_print_context(p_ythread, p_os, 0); -+ fprintf(p_os, -+ "stack : %p\n" -+ "stacksize : %" PRIu64 "\n", -+ p_ythread->p_stack, (uint64_t)p_ythread->stacksize); -+ -+#ifdef ABT_CONFIG_ENABLE_STACK_UNWIND -+ { -+ /* Peeking a running context is specially forbidden. Though it is -+ * incomplete, let's quickly check if a thread is running. */ -+ ABT_thread_state state = (ABT_thread_state)ABTD_atomic_acquire_load_int( -+ &p_ythread->thread.state); -+ if (state == ABT_THREAD_STATE_READY || -+ state == ABT_THREAD_STATE_BLOCKED) { -+ struct unwind_stack_t arg; -+ arg.fp = p_os; -+ ABTI_ythread_context_peek(p_ythread, ythread_unwind_stack, &arg); -+ } -+ } -+#endif -+ - void *p_stack = p_ythread->p_stack; - size_t i, j, stacksize = p_ythread->stacksize; - if (stacksize == 0 || p_stack == NULL) { - /* Some threads do not have p_stack (e.g., the main thread) */ -+ fprintf(p_os, "no stack\n"); -+ fflush(0); - return; - } - -@@ -131,4 +169,56 @@ ABTU_no_sanitize_address void ABTI_ythread_print_stack(ABTI_ythread *p_ythread, - fprintf(p_os, "\n"); - } - } -+ fflush(p_os); - } -+ -+#ifdef ABT_CONFIG_ENABLE_STACK_UNWIND -+ABTU_no_sanitize_address static int ythread_unwind_stack_impl(FILE *fp) -+{ -+ unw_cursor_t cursor; -+ unw_context_t uc; -+ unw_word_t ip, sp; -+ int ret, level = -1; -+ -+ ret = unw_getcontext(&uc); -+ if (ret != 0) -+ return ABT_ERR_OTHER; -+ -+ ret = unw_init_local(&cursor, &uc); -+ if (ret != 0) -+ return ABT_ERR_OTHER; -+ -+ while (unw_step(&cursor) > 0 && level < 50) { -+ level++; -+ -+ ret = unw_get_reg(&cursor, UNW_REG_IP, &ip); -+ if (ret != 0) -+ return ABT_ERR_OTHER; -+ -+ ret = unw_get_reg(&cursor, UNW_REG_SP, &sp); -+ if (ret != 0) -+ return ABT_ERR_OTHER; -+ -+ char proc_name[256]; -+ unw_word_t offset; -+ ret = unw_get_proc_name(&cursor, proc_name, 256, &offset); -+ if (ret != 0) -+ return ABT_ERR_OTHER; -+ -+ /* Print function stack. */ -+ fprintf(fp, "#%d %p in %s () <+%d> (%s = %p)\n", level, -+ (void *)((uintptr_t)ip), proc_name, (int)offset, -+ unw_regname(UNW_REG_SP), (void *)((uintptr_t)sp)); -+ } -+ return ABT_SUCCESS; -+} -+ -+static void ythread_unwind_stack(void *arg) -+{ -+ struct unwind_stack_t *p_arg = (struct unwind_stack_t *)arg; -+ if (ythread_unwind_stack_impl(p_arg->fp) != ABT_SUCCESS) { -+ fprintf(p_arg->fp, "libunwind error\n"); -+ } -+} -+ -+#endif /* ABT_CONFIG_ENABLE_STACK_UNWIND */ -diff --git a/src/ythread_htable.c b/src/ythread_htable.c -deleted file mode 100644 -index 3678385..0000000 ---- a/src/ythread_htable.c -+++ /dev/null -@@ -1,218 +0,0 @@ --/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */ --/* -- * See COPYRIGHT in top-level directory. -- */ -- --#include "abti.h" --#include "abti_ythread_htable.h" -- --ABTU_ret_err int ABTI_ythread_htable_create(uint32_t num_rows, -- ABTI_ythread_htable **pp_htable) --{ -- ABTI_STATIC_ASSERT(sizeof(ABTI_ythread_queue) == 192); -- -- int abt_errno; -- ABTI_ythread_htable *p_htable; -- size_t q_size = num_rows * sizeof(ABTI_ythread_queue); -- -- abt_errno = ABTU_malloc(sizeof(ABTI_ythread_htable), (void **)&p_htable); -- ABTI_CHECK_ERROR(abt_errno); -- -- abt_errno = ABTU_memalign(64, q_size, (void **)&p_htable->queue); -- if (ABTI_IS_ERROR_CHECK_ENABLED && abt_errno != ABT_SUCCESS) { -- ABTU_free(p_htable); -- return abt_errno; -- } -- memset(p_htable->queue, 0, q_size); -- --#if defined(HAVE_LH_LOCK_H) -- lh_lock_init(&p_htable->mutex); --#elif defined(HAVE_CLH_H) -- clh_init(&p_htable->mutex); --#elif defined(USE_PTHREAD_MUTEX) -- int ret = pthread_mutex_init(&p_htable->mutex, NULL); -- if (ret) { -- ABTU_free(p_htable->queue); -- ABTU_free(p_htable); -- return ABT_ERR_OTHER; -- } --#else -- ABTI_spinlock_clear(&p_htable->mutex); --#endif -- ABTD_atomic_relaxed_store_uint32(&p_htable->num_elems, 0); -- p_htable->num_rows = num_rows; -- p_htable->h_list = NULL; -- p_htable->l_list = NULL; -- *pp_htable = p_htable; -- return ABT_SUCCESS; --} -- --void ABTI_ythread_htable_free(ABTI_ythread_htable *p_htable) --{ -- ABTI_ASSERT(ABTD_atomic_relaxed_load_uint32(&p_htable->num_elems) == 0); -- --#if defined(HAVE_LH_LOCK_H) -- lh_lock_destroy(&p_htable->mutex); --#elif defined(HAVE_CLH_H) -- clh_destroy(&p_htable->mutex); --#elif defined(USE_PTHREAD_MUTEX) -- int ret = pthread_mutex_destroy(&p_htable->mutex); -- assert(!ret); --#else -- /* ABTI_spinlock needs no finalization. */ --#endif -- ABTU_free(p_htable->queue); -- ABTU_free(p_htable); --} -- --void ABTI_ythread_htable_push(ABTI_ythread_htable *p_htable, int idx, -- ABTI_ythread *p_ythread) --{ -- ABTI_ythread_queue *p_queue; -- -- if (idx >= p_htable->num_rows) { -- ABTI_ASSERT(0); -- ABTU_unreachable(); -- } -- -- /* Add p_ythread to the end of the idx-th row */ -- p_queue = &p_htable->queue[idx]; -- ABTI_ythread_queue_acquire_mutex(p_queue); -- if (p_queue->head == NULL) { -- p_queue->head = p_ythread; -- p_queue->tail = p_ythread; -- } else { -- p_queue->tail->thread.p_next = &p_ythread->thread; -- p_queue->tail = p_ythread; -- } -- p_queue->num_threads++; -- ABTI_ythread_queue_release_mutex(p_queue); -- ABTD_atomic_fetch_add_uint32(&p_htable->num_elems, 1); --} -- --void ABTI_ythread_htable_push_low(ABTI_ythread_htable *p_htable, int idx, -- ABTI_ythread *p_ythread) --{ -- ABTI_ythread_queue *p_queue; -- -- if (idx >= p_htable->num_rows) { -- ABTI_ASSERT(0); -- ABTU_unreachable(); -- } -- -- /* Add p_ythread to the end of the idx-th row */ -- p_queue = &p_htable->queue[idx]; -- ABTI_ythread_queue_acquire_low_mutex(p_queue); -- if (p_queue->low_head == NULL) { -- p_queue->low_head = p_ythread; -- p_queue->low_tail = p_ythread; -- } else { -- p_queue->low_tail->thread.p_next = &p_ythread->thread; -- p_queue->low_tail = p_ythread; -- } -- p_queue->low_num_threads++; -- ABTI_ythread_queue_release_low_mutex(p_queue); -- ABTD_atomic_fetch_add_uint32(&p_htable->num_elems, 1); --} -- --ABTI_ythread *ABTI_ythread_htable_pop(ABTI_ythread_htable *p_htable, -- ABTI_ythread_queue *p_queue) --{ -- ABTI_ythread *p_ythread = NULL; -- -- ABTI_ythread_queue_acquire_mutex(p_queue); -- if (p_queue->head) { -- ABTD_atomic_fetch_sub_uint32(&p_htable->num_elems, 1); -- p_ythread = p_queue->head; -- if (p_queue->head == p_queue->tail) { -- p_queue->head = NULL; -- p_queue->tail = NULL; -- } else { -- p_queue->head = ABTI_thread_get_ythread(p_ythread->thread.p_next); -- } -- -- p_queue->num_threads--; -- } -- ABTI_ythread_queue_release_mutex(p_queue); -- -- return p_ythread; --} -- --ABTI_ythread *ABTI_ythread_htable_pop_low(ABTI_ythread_htable *p_htable, -- ABTI_ythread_queue *p_queue) --{ -- ABTI_ythread *p_ythread = NULL; -- -- ABTI_ythread_queue_acquire_low_mutex(p_queue); -- if (p_queue->low_head) { -- ABTD_atomic_fetch_sub_uint32(&p_htable->num_elems, 1); -- p_ythread = p_queue->low_head; -- if (p_queue->low_head == p_queue->low_tail) { -- p_queue->low_head = NULL; -- p_queue->low_tail = NULL; -- } else { -- p_queue->low_head = -- ABTI_thread_get_ythread(p_ythread->thread.p_next); -- } -- -- p_queue->low_num_threads--; -- } -- ABTI_ythread_queue_release_low_mutex(p_queue); -- -- return p_ythread; --} -- --ABT_bool ABTI_ythread_htable_switch_low(ABTI_xstream **pp_local_xstream, -- ABTI_ythread_queue *p_queue, -- ABTI_ythread *p_ythread, -- ABTI_ythread_htable *p_htable, -- ABT_sync_event_type sync_event_type, -- void *p_sync) --{ -- ABTI_ythread *p_target = NULL; -- ABTI_xstream *p_local_xstream = *pp_local_xstream; -- -- ABTI_ythread_queue_acquire_low_mutex(p_queue); -- if (p_queue->low_head) { -- p_target = p_queue->low_head; -- -- /* Push p_ythread to the queue */ -- ABTD_atomic_release_store_int(&p_ythread->thread.state, -- ABT_THREAD_STATE_BLOCKED); -- ABTI_tool_event_ythread_suspend(p_local_xstream, p_ythread, -- p_ythread->thread.p_parent, -- sync_event_type, p_sync); -- if (p_queue->low_head == p_queue->low_tail) { -- p_queue->low_head = p_ythread; -- p_queue->low_tail = p_ythread; -- } else { -- p_queue->low_head = -- ABTI_thread_get_ythread(p_target->thread.p_next); -- p_queue->low_tail->thread.p_next = &p_ythread->thread; -- p_queue->low_tail = p_ythread; -- } -- } -- ABTI_ythread_queue_release_low_mutex(p_queue); -- -- if (p_target) { -- LOG_DEBUG("switch -> U%" PRIu64 "\n", -- ABTI_thread_get_id(&p_target->thread)); -- -- /* Context-switch to p_target */ -- ABTD_atomic_release_store_int(&p_target->thread.state, -- ABT_THREAD_STATE_RUNNING); -- ABTI_tool_event_ythread_resume(ABTI_xstream_get_local(p_local_xstream), -- p_target, -- p_local_xstream -- ? p_local_xstream->p_thread -- : NULL); -- ABTI_ythread *p_prev = -- ABTI_ythread_context_switch_to_sibling(pp_local_xstream, p_ythread, -- p_target); -- ABTI_tool_event_thread_run(*pp_local_xstream, &p_ythread->thread, -- &p_prev->thread, p_ythread->thread.p_parent); -- return ABT_TRUE; -- } else { -- return ABT_FALSE; -- } --} -diff --git a/test/basic/Makefile.am b/test/basic/Makefile.am -index fe9204b..56d6918 100644 ---- a/test/basic/Makefile.am -+++ b/test/basic/Makefile.am -@@ -15,6 +15,7 @@ TESTS = \ - thread_create_on_xstream \ - thread_revive \ - thread_attr \ -+ thread_attr2 \ - thread_yield \ - thread_yield_to \ - thread_self_suspend_resume \ -@@ -62,8 +63,10 @@ TESTS = \ - ext_thread2 \ - timer \ - info_print \ -+ info_print_stack \ - info_stackdump \ -- info_stackdump2 -+ info_stackdump2 \ -+ error - - XFAIL_TESTS = - if ABT_CONFIG_DISABLE_EXT_THREAD -@@ -89,6 +92,7 @@ thread_create2_SOURCES = thread_create2.c - thread_create_on_xstream_SOURCES = thread_create_on_xstream.c - thread_revive_SOURCES = thread_revive.c - thread_attr_SOURCES = thread_attr.c -+thread_attr2_SOURCES = thread_attr2.c - thread_yield_SOURCES = thread_yield.c - thread_yield_to_SOURCES = thread_yield_to.c - thread_self_suspend_resume_SOURCES = thread_self_suspend_resume.c -@@ -136,8 +140,10 @@ ext_thread_SOURCES = ext_thread.c - ext_thread2_SOURCES = ext_thread2.c - timer_SOURCES = timer.c - info_print_SOURCES = info_print.c -+info_print_stack_SOURCES = info_print_stack.c - info_stackdump_SOURCES = info_stackdump.c - info_stackdump2_SOURCES = info_stackdump2.c -+error_SOURCES = error.c - - testing: - ./init_finalize -@@ -151,6 +157,7 @@ testing: - ./thread_create_on_xstream - ./thread_revive - ./thread_attr -+ ./thread_attr2 - ./thread_yield - ./thread_yield_to - ./thread_self_suspend_resume -@@ -198,5 +205,7 @@ testing: - ./ext_thread2 - ./timer - ./info_print -+ ./info_print_stack - ./info_stackdump - ./info_stackdump2 -+ ./error -diff --git a/test/basic/error.c b/test/basic/error.c -new file mode 100644 -index 0000000..a0ccfcd ---- /dev/null -+++ b/test/basic/error.c -@@ -0,0 +1,86 @@ -+/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */ -+/* -+ * See COPYRIGHT in top-level directory. -+ */ -+ -+#include -+#include -+#include -+#include "abt.h" -+#include "abttest.h" -+ -+typedef struct { -+ const char *str; -+ int code; -+} error_pair_t; -+ -+int main(int argc, char *argv[]) -+{ -+ int ret, i; -+ -+ /* init and thread creation */ -+ ATS_read_args(argc, argv); -+ -+ error_pair_t error_pairs[] = { -+ { "ABT_SUCCESS", ABT_SUCCESS }, -+ { "ABT_ERR_UNINITIALIZED", ABT_ERR_UNINITIALIZED }, -+ { "ABT_ERR_MEM", ABT_ERR_MEM }, -+ { "ABT_ERR_OTHER", ABT_ERR_OTHER }, -+ { "ABT_ERR_INV_XSTREAM", ABT_ERR_INV_XSTREAM }, -+ { "ABT_ERR_INV_XSTREAM_RANK", ABT_ERR_INV_XSTREAM_RANK }, -+ { "ABT_ERR_INV_XSTREAM_BARRIER", ABT_ERR_INV_XSTREAM_BARRIER }, -+ { "ABT_ERR_INV_SCHED", ABT_ERR_INV_SCHED }, -+ { "ABT_ERR_INV_SCHED_KIND", ABT_ERR_INV_SCHED_KIND }, -+ { "ABT_ERR_INV_SCHED_PREDEF", ABT_ERR_INV_SCHED_PREDEF }, -+ { "ABT_ERR_INV_SCHED_TYPE", ABT_ERR_INV_SCHED_TYPE }, -+ { "ABT_ERR_INV_SCHED_CONFIG", ABT_ERR_INV_SCHED_CONFIG }, -+ { "ABT_ERR_INV_POOL", ABT_ERR_INV_POOL }, -+ { "ABT_ERR_INV_POOL_KIND", ABT_ERR_INV_POOL_KIND }, -+ { "ABT_ERR_INV_POOL_ACCESS", ABT_ERR_INV_POOL_ACCESS }, -+ { "ABT_ERR_INV_UNIT", ABT_ERR_INV_UNIT }, -+ { "ABT_ERR_INV_THREAD", ABT_ERR_INV_THREAD }, -+ { "ABT_ERR_INV_THREAD_ATTR", ABT_ERR_INV_THREAD_ATTR }, -+ { "ABT_ERR_INV_KEY", ABT_ERR_INV_KEY }, -+ { "ABT_ERR_INV_MUTEX", ABT_ERR_INV_MUTEX }, -+ { "ABT_ERR_INV_MUTEX_ATTR", ABT_ERR_INV_MUTEX_ATTR }, -+ { "ABT_ERR_INV_COND", ABT_ERR_INV_COND }, -+ { "ABT_ERR_INV_RWLOCK", ABT_ERR_INV_RWLOCK }, -+ { "ABT_ERR_INV_EVENTUAL", ABT_ERR_INV_EVENTUAL }, -+ { "ABT_ERR_INV_FUTURE", ABT_ERR_INV_FUTURE }, -+ { "ABT_ERR_INV_BARRIER", ABT_ERR_INV_BARRIER }, -+ { "ABT_ERR_INV_TIMER", ABT_ERR_INV_TIMER }, -+ { "ABT_ERR_INV_QUERY_KIND", ABT_ERR_INV_QUERY_KIND }, -+ { "ABT_ERR_XSTREAM", ABT_ERR_XSTREAM }, -+ { "ABT_ERR_XSTREAM_STATE", ABT_ERR_XSTREAM_STATE }, -+ { "ABT_ERR_XSTREAM_BARRIER", ABT_ERR_XSTREAM_BARRIER }, -+ { "ABT_ERR_SCHED", ABT_ERR_SCHED }, -+ { "ABT_ERR_SCHED_CONFIG", ABT_ERR_SCHED_CONFIG }, -+ { "ABT_ERR_POOL", ABT_ERR_POOL }, -+ { "ABT_ERR_UNIT", ABT_ERR_UNIT }, -+ { "ABT_ERR_THREAD", ABT_ERR_THREAD }, -+ { "ABT_ERR_KEY", ABT_ERR_KEY }, -+ { "ABT_ERR_MUTEX", ABT_ERR_MUTEX }, -+ { "ABT_ERR_MUTEX_LOCKED", ABT_ERR_MUTEX_LOCKED }, -+ { "ABT_ERR_COND", ABT_ERR_COND }, -+ { "ABT_ERR_COND_TIMEDOUT", ABT_ERR_COND_TIMEDOUT }, -+ { "ABT_ERR_RWLOCK", ABT_ERR_RWLOCK }, -+ { "ABT_ERR_EVENTUAL", ABT_ERR_EVENTUAL }, -+ { "ABT_ERR_FUTURE", ABT_ERR_FUTURE }, -+ { "ABT_ERR_BARRIER", ABT_ERR_BARRIER }, -+ { "ABT_ERR_TIMER", ABT_ERR_TIMER }, -+ { "ABT_ERR_MIGRATION_TARGET", ABT_ERR_MIGRATION_TARGET }, -+ { "ABT_ERR_MIGRATION_NA", ABT_ERR_MIGRATION_NA }, -+ { "ABT_ERR_MISSING_JOIN", ABT_ERR_MISSING_JOIN }, -+ { "ABT_ERR_FEATURE_NA", ABT_ERR_FEATURE_NA }, -+ { "ABT_ERR_INV_TOOL_CONTEXT", ABT_ERR_INV_TOOL_CONTEXT }, -+ { "ABT_ERR_INV_ARG", ABT_ERR_INV_ARG }, -+ }; -+ -+ for (i = 0; i < (int)(sizeof(error_pairs) / sizeof(error_pairs[0])); i++) { -+ char str[256]; -+ ret = ABT_error_get_str(error_pairs[i].code, str, NULL); -+ ATS_ERROR(ret, "ABT_error_get_str"); -+ assert(strcmp(error_pairs[i].str, str) == 0); -+ } -+ return ret; -+} -diff --git a/test/basic/eventual_create.c b/test/basic/eventual_create.c -index 81a2fc4..2cda2c9 100644 ---- a/test/basic/eventual_create.c -+++ b/test/basic/eventual_create.c -@@ -30,7 +30,8 @@ void fn1(void *args) - void fn2(void *args) - { - ATS_UNUSED(args); -- int i = 0, is_ready = 0; -+ int i = 0; -+ ABT_bool is_ready = 0; - void *data; - ATS_printf(1, "Thread 2 iteration %d waiting from eventual\n", i); - ABT_eventual_test(myeventual, &data, &is_ready); -diff --git a/test/basic/info_print_stack.c b/test/basic/info_print_stack.c -new file mode 100644 -index 0000000..6b5b5ea ---- /dev/null -+++ b/test/basic/info_print_stack.c -@@ -0,0 +1,178 @@ -+/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */ -+/* -+ * See COPYRIGHT in top-level directory. -+ */ -+ -+#include -+#include -+#include -+#include "abt.h" -+#include "abttest.h" -+ -+#define DEFAULT_NUM_THREADS 10 -+ -+volatile int g_go = 0; -+ -+typedef struct thread_arg { -+ int id; -+ int level; -+ void *stack; -+} thread_arg_t; -+ -+void user_thread_func_lv4(int level) -+{ -+ while (g_go == 0) { -+ int ret = ABT_thread_yield(); -+ ATS_ERROR(ret, "ABT_thread_yield"); -+ } -+} -+ -+void user_thread_func_lv3(int level) -+{ -+ if (level == 0) { -+ while (g_go == 0) { -+ int ret = ABT_thread_yield(); -+ ATS_ERROR(ret, "ABT_thread_yield"); -+ } -+ } else { -+ user_thread_func_lv4(level - 1); -+ } -+ user_thread_func_lv4(level - 1); -+} -+ -+void user_thread_func_lv2(int level) -+{ -+ if (level == 0) { -+ while (g_go == 0) { -+ int ret = ABT_thread_yield(); -+ ATS_ERROR(ret, "ABT_thread_yield"); -+ } -+ } else { -+ user_thread_func_lv3(level - 1); -+ } -+ user_thread_func_lv3(level - 1); -+} -+ -+void user_thread_func(void *arg) -+{ -+ thread_arg_t *t_arg = (thread_arg_t *)arg; -+ int level = t_arg->level; -+ if (level == 0) { -+ while (g_go == 0) { -+ int ret = ABT_thread_yield(); -+ ATS_ERROR(ret, "ABT_thread_yield"); -+ } -+ } else { -+ user_thread_func_lv2(level - 1); -+ } -+ user_thread_func_lv2(level - 1); -+} -+ -+static inline void create_thread(ABT_pool pool, ABT_thread *threads, -+ thread_arg_t *args, int i) -+{ -+ int ret; -+ args[i].id = i; -+ args[i].level = i % 4; -+ args[i].stack = NULL; -+ if (i % 3 == 0) { -+ ret = ABT_thread_create(pool, user_thread_func, (void *)&args[i], -+ ABT_THREAD_ATTR_NULL, &threads[i]); -+ ATS_ERROR(ret, "ABT_thread_create"); -+ } else if (i % 3 == 1) { -+ ABT_thread_attr attr; -+ ret = ABT_thread_attr_create(&attr); -+ ATS_ERROR(ret, "ABT_thread_attr_create"); -+ ret = ABT_thread_attr_set_stacksize(attr, 32768); -+ ATS_ERROR(ret, "ABT_thread_attr_set_stacksize"); -+ ret = ABT_thread_create(pool, user_thread_func, (void *)&args[i], attr, -+ &threads[i]); -+ ATS_ERROR(ret, "ABT_thread_create"); -+ ret = ABT_thread_attr_free(&attr); -+ ATS_ERROR(ret, "ABT_thread_attr_free"); -+ } else { -+ const size_t stacksize = 32768; -+ args[i].stack = malloc(stacksize); -+ ABT_thread_attr attr; -+ ret = ABT_thread_attr_create(&attr); -+ ATS_ERROR(ret, "ABT_thread_attr_create"); -+ ret = ABT_thread_attr_set_stack(attr, args[i].stack, stacksize); -+ ATS_ERROR(ret, "ABT_thread_attr_set_stack"); -+ ret = ABT_thread_create(pool, user_thread_func, (void *)&args[i], attr, -+ &threads[i]); -+ ATS_ERROR(ret, "ABT_thread_create"); -+ ret = ABT_thread_attr_free(&attr); -+ ATS_ERROR(ret, "ABT_thread_attr_free"); -+ } -+} -+ -+int main(int argc, char *argv[]) -+{ -+ int i; -+ int ret; -+ int num_threads = DEFAULT_NUM_THREADS; -+ -+ /* Initialize */ -+ ATS_read_args(argc, argv); -+ if (argc >= 2) { -+ num_threads = ATS_get_arg_val(ATS_ARG_N_ULT); -+ } -+ ATS_init(argc, argv, 1); -+ -+ ATS_printf(2, "# of ESs : 1\n"); -+ ATS_printf(1, "# of ULTs: %d\n", num_threads); -+ -+ ABT_xstream xstream; -+ ABT_thread *threads = -+ (ABT_thread *)malloc(sizeof(ABT_thread) * num_threads); -+ thread_arg_t *args = -+ (thread_arg_t *)malloc(sizeof(thread_arg_t) * num_threads); -+ -+ /* Create execution streams */ -+ ret = ABT_xstream_self(&xstream); -+ ATS_ERROR(ret, "ABT_xstream_self"); -+ -+ /* Get the pools attached to an execution stream */ -+ ABT_pool pool; -+ ret = ABT_xstream_get_main_pools(xstream, 1, &pool); -+ ATS_ERROR(ret, "ABT_xstream_get_main_pools"); -+ -+ /* Create the first (num_threads - 4) threads, which will be executed. */ -+ for (i = 0; i < num_threads - 4; i++) -+ create_thread(pool, threads, args, i); -+ -+ /* Execute some of the threads. */ -+ ret = ABT_thread_yield(); -+ ATS_ERROR(ret, "ABT_thread_yield"); -+ -+ /* Create the last four threads, which are not executed. */ -+ for (i = num_threads - 4; i < num_threads; i++) -+ create_thread(pool, threads, args, i); -+ -+ /* Print unwinded stacks. */ -+ for (i = 0; i < num_threads; i++) { -+ printf("threads[%d]:\n", i); -+ ret = ABT_info_print_thread_stack(stdout, threads[i]); -+ ATS_ERROR(ret, "ABT_info_print_thread_stack"); -+ printf("\n"); -+ } -+ g_go = 1; -+ -+ /* Join and free ULTs */ -+ for (i = 0; i < num_threads; i++) { -+ ret = ABT_thread_free(&threads[i]); -+ ATS_ERROR(ret, "ABT_thread_free"); -+ } -+ -+ /* Finalize */ -+ ret = ATS_finalize(0); -+ -+ for (i = 0; i < num_threads; i++) { -+ if (args[i].stack) -+ free(args[i].stack); -+ } -+ free(threads); -+ free(args); -+ -+ return ret; -+} -diff --git a/test/basic/sched_set_main.c b/test/basic/sched_set_main.c -index d96814f..7a199a2 100644 ---- a/test/basic/sched_set_main.c -+++ b/test/basic/sched_set_main.c -@@ -78,9 +78,8 @@ static void thread_func(void *arg) - - int main(int argc, char *argv[]) - { -- size_t i; - int ret; -- int num_xstreams = DEFAULT_NUM_XSTREAMS; -+ int i, num_xstreams = DEFAULT_NUM_XSTREAMS; - ABT_xstream *xstreams; - ABT_pool *pools; - ABT_thread *threads; -@@ -114,7 +113,7 @@ int main(int argc, char *argv[]) - - /* Create ULTs */ - for (i = 1; i < num_xstreams; i++) { -- ret = ABT_thread_create(pools[i], thread_func, (void *)i, -+ ret = ABT_thread_create(pools[i], thread_func, (void *)((uintptr_t)i), - ABT_THREAD_ATTR_NULL, &threads[i]); - ATS_ERROR(ret, "ABT_thread_create"); - } -diff --git a/test/basic/thread_attr2.c b/test/basic/thread_attr2.c -new file mode 100644 -index 0000000..e8eaa14 ---- /dev/null -+++ b/test/basic/thread_attr2.c -@@ -0,0 +1,205 @@ -+/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */ -+/* -+ * See COPYRIGHT in top-level directory. -+ */ -+ -+#include -+#include -+#include "abt.h" -+#include "abttest.h" -+ -+#define DEFAULT_NUM_XSTREAMS 4 -+#define DEFAULT_NUM_THREADS 4 -+ -+#define DUMMY_SIZE ((int)(1024 / sizeof(double))) -+void set_random_dummy(volatile double *dummy) -+{ -+ int i; -+ double base_value = ABT_get_wtime(); -+ for (i = 0; i < DUMMY_SIZE; i++) -+ dummy[i] = base_value + i; -+} -+ -+void update_random_dummy(volatile double *dummy) -+{ -+ int i; -+ double base_value = ABT_get_wtime(); -+ for (i = 0; i < DUMMY_SIZE; i++) { -+ if (dummy[i] == base_value + i) -+ dummy[i] *= 1.5; -+ } -+} -+ -+void dummy_rec(const volatile double *top_dummy, volatile double *prev_dummy, -+ size_t stacksize) -+{ -+ int i; -+ volatile double dummy[DUMMY_SIZE]; -+ set_random_dummy(dummy); -+ -+ uintptr_t dummy_ptr = (uintptr_t)dummy; -+ uintptr_t top_dummy_ptr = (uintptr_t)top_dummy; -+ if (top_dummy_ptr > dummy_ptr) { -+ if ((size_t)(top_dummy_ptr - dummy_ptr) > stacksize / 2) -+ /* Consumed enough stack. */ -+ return; -+ } else { -+ if ((size_t)(dummy_ptr - top_dummy_ptr) > stacksize / 2) -+ /* Consumed enough stack. */ -+ return; -+ } -+ /* Recursive call. */ -+ dummy_rec(top_dummy, dummy, stacksize); -+ /* We need to avoid tail recursion elimination, so let's do something. */ -+ update_random_dummy(dummy); -+ for (i = 0; i < DUMMY_SIZE; i++) -+ prev_dummy[i] += dummy[i]; -+} -+ -+void thread_func(void *arg) -+{ -+ size_t stacksize = *((size_t *)arg), stacksize2; -+ ABT_thread thread; -+ ABT_thread_attr attr; -+ int ret, i; -+ -+ ret = ABT_thread_self(&thread); -+ ATS_ERROR(ret, "ABT_thread_self"); -+ ret = ABT_thread_get_attr(thread, &attr); -+ ATS_ERROR(ret, "ABT_thread_get_attr"); -+ -+ ret = ABT_thread_attr_get_stacksize(attr, &stacksize2); -+ ATS_ERROR(ret, "ABT_thread_attr_get_stacksize"); -+ /* This must be the same. */ -+ assert(stacksize == stacksize2); -+ -+ /* -+ * Checking a real stack size is tricky. Let's consume stack by recursion. -+ * - Each dummy_rec() consumes at least "DUMMY_SIZE * sizeof(double)" bytes. -+ * - Call dummy_rec() recursively until the total stack consumption gets -+ * more than half of stacksize. We need a margin for safety since we -+ * cannot control the exact size of each function stack. -+ * Note that we use neither alloca() nor variable-length array since they -+ * are not portable. -+ */ -+ volatile double dummy[DUMMY_SIZE]; -+ set_random_dummy(dummy); -+ dummy_rec(dummy, dummy, stacksize); -+ -+ update_random_dummy(dummy); -+ /* Use values of dummy to avoid possible compiler optimization */ -+ for (i = 0; i < DUMMY_SIZE; i++) { -+ if (0.00001 < dummy[i] && dummy[i] < 0.00002) -+ printf("%d %f", i, dummy[i]); -+ } -+ -+ ret = ABT_thread_attr_free(&attr); -+ ATS_ERROR(ret, "ABT_thread_attr_free"); -+} -+ -+int main(int argc, char *argv[]) -+{ -+ int ret, i; -+ -+ ABT_thread_attr attr; -+ ABT_xstream xstream; -+ ABT_pool pool; -+ ABT_thread thread; -+ -+ /* Initialize */ -+ ATS_read_args(argc, argv); -+ ATS_init(argc, argv, 1); -+ -+ /* Get a main pool. */ -+ ret = ABT_xstream_self(&xstream); -+ ATS_ERROR(ret, "ABT_xstream_self"); -+ ret = ABT_xstream_get_main_pools(xstream, 1, &pool); -+ ATS_ERROR(ret, "ABT_xstream_get_main_pools"); -+ -+ /* Get the default stack size. */ -+ size_t default_stacksize; -+ ret = ABT_info_query_config(ABT_INFO_QUERY_KIND_DEFAULT_THREAD_STACKSIZE, -+ &default_stacksize); -+ ATS_ERROR(ret, "ABT_info_query_config"); -+ -+ /* Loop over different stack sizes. */ -+ size_t stacksizes[] = { default_stacksize, 1024 * 64, 1024 * 1024 }; -+ int num_stacksizes = sizeof(stacksizes) / sizeof(stacksizes[0]); -+ for (i = 0; i < num_stacksizes; i++) { -+ size_t stacksize = stacksizes[i]; -+ -+ ret = ABT_thread_attr_create(&attr); -+ ATS_ERROR(ret, "ABT_thread_attr_create"); -+ -+ /* Case 1: set it via ABT_thread_attr_set_stacksize() */ -+ ret = ABT_thread_attr_set_stacksize(attr, stacksize); -+ ATS_ERROR(ret, "ABT_thread_attr_set_stacksize"); -+ ret = ABT_thread_create(pool, thread_func, (void *)&stacksize, attr, -+ &thread); -+ ATS_ERROR(ret, "ABT_thread_create"); -+ ret = ABT_thread_free(&thread); -+ ATS_ERROR(ret, "ABT_thread_free"); -+ -+ /* Case 2: set it via ABT_thread_attr_set_stack() (stack: NULL) */ -+ ret = ABT_thread_attr_set_stack(attr, NULL, stacksize); -+ ATS_ERROR(ret, "ABT_thread_attr_set_stack"); -+ ret = ABT_thread_create(pool, thread_func, (void *)&stacksize, attr, -+ &thread); -+ ATS_ERROR(ret, "ABT_thread_create"); -+ ret = ABT_thread_free(&thread); -+ ATS_ERROR(ret, "ABT_thread_free"); -+ -+ /* Case 3: set a different value once. */ -+ ret = -+ ABT_thread_attr_set_stacksize(attr, -+ stacksizes[(i + 1) % num_stacksizes]); -+ ATS_ERROR(ret, "ABT_thread_attr_set_stack_size"); -+ ret = ABT_thread_attr_set_stacksize(attr, stacksize); -+ ATS_ERROR(ret, "ABT_thread_attr_set_stack_size"); -+ ret = ABT_thread_create(pool, thread_func, (void *)&stacksize, attr, -+ &thread); -+ ATS_ERROR(ret, "ABT_thread_create"); -+ ret = ABT_thread_free(&thread); -+ ATS_ERROR(ret, "ABT_thread_free"); -+ -+ /* Case 4: use ABT_thread_attr_set_stack() with stack. */ -+ void *p_stack1 = (void *)malloc(stacksize); -+ ret = ABT_thread_attr_set_stack(attr, p_stack1, stacksize); -+ ATS_ERROR(ret, "ABT_thread_attr_set_stack"); -+ ret = ABT_thread_create(pool, thread_func, (void *)&stacksize, attr, -+ &thread); -+ ATS_ERROR(ret, "ABT_thread_create"); -+ ret = ABT_thread_free(&thread); -+ ATS_ERROR(ret, "ABT_thread_free"); -+ free(p_stack1); -+ -+ /* Case 5: set a different value once. */ -+ void *p_stack2 = (void *)malloc(stacksize); -+ ret = ABT_thread_attr_set_stack(attr, p_stack2, -+ stacksizes[(i + 1) % num_stacksizes]); -+ ATS_ERROR(ret, "ABT_thread_attr_set_stack"); -+ ret = ABT_thread_attr_set_stacksize(attr, stacksize); -+ ATS_ERROR(ret, "ABT_thread_attr_set_stack_size"); -+ ret = ABT_thread_create(pool, thread_func, (void *)&stacksize, attr, -+ &thread); -+ ATS_ERROR(ret, "ABT_thread_create"); -+ ret = ABT_thread_free(&thread); -+ ATS_ERROR(ret, "ABT_thread_free"); -+ free(p_stack2); -+ -+ ret = ABT_thread_attr_free(&attr); -+ ATS_ERROR(ret, "ABT_thread_attr_free"); -+ } -+ -+ /* Case 6: default attribute. */ -+ ret = ABT_thread_create(pool, thread_func, (void *)&default_stacksize, -+ ABT_THREAD_ATTR_NULL, &thread); -+ ATS_ERROR(ret, "ABT_thread_create"); -+ ret = ABT_thread_free(&thread); -+ ATS_ERROR(ret, "ABT_thread_free"); -+ -+ /* Finalize */ -+ ret = ATS_finalize(0); -+ -+ return ret; -+} -diff --git a/test/benchmark/task_ops_all.c b/test/benchmark/task_ops_all.c -index fb813b5..8367a5f 100644 ---- a/test/benchmark/task_ops_all.c -+++ b/test/benchmark/task_ops_all.c -@@ -66,7 +66,7 @@ int main(int argc, char *argv[]) - ABT_pool(*all_pools)[2]; - ABT_sched *scheds; - ABT_thread *top_threads; -- size_t i, t; -+ int i, t; - uint64_t t_start; - - /* read command-line arguments */ -@@ -128,7 +128,7 @@ int main(int argc, char *argv[]) - - /* warm-up */ - for (i = 0; i < num_xstreams; i++) { -- ABT_thread_create(all_pools[i][0], test_fn, (void *)i, -+ ABT_thread_create(all_pools[i][0], test_fn, (void *)((uintptr_t)i), - ABT_THREAD_ATTR_NULL, &top_threads[i]); - } - for (i = 0; i < num_xstreams; i++) { -@@ -138,7 +138,7 @@ int main(int argc, char *argv[]) - /* measurement */ - t_start = ATS_get_cycles(); - for (i = 0; i < num_xstreams; i++) { -- ABT_thread_create(all_pools[i][0], test_fn, (void *)i, -+ ABT_thread_create(all_pools[i][0], test_fn, (void *)((uintptr_t)i), - ABT_THREAD_ATTR_NULL, &top_threads[i]); - } - for (i = 0; i < num_xstreams; i++) { -diff --git a/test/benchmark/thread_ops_all.c b/test/benchmark/thread_ops_all.c -index 96be1df..5f1ac24 100644 ---- a/test/benchmark/thread_ops_all.c -+++ b/test/benchmark/thread_ops_all.c -@@ -285,7 +285,7 @@ int main(int argc, char *argv[]) - ABT_pool(*all_pools)[2]; - ABT_sched *scheds; - ABT_thread *top_threads; -- size_t i, t; -+ int i, t; - uint64_t t_start; - - /* read command-line arguments */ -@@ -381,7 +381,7 @@ int main(int argc, char *argv[]) - - /* warm-up */ - for (i = 0; i < num_xstreams; i++) { -- ABT_thread_create(all_pools[i][0], test_fn, (void *)i, -+ ABT_thread_create(all_pools[i][0], test_fn, (void *)((uintptr_t)i), - ABT_THREAD_ATTR_NULL, &top_threads[i]); - } - for (i = 0; i < num_xstreams; i++) { -@@ -395,7 +395,7 @@ int main(int argc, char *argv[]) - t_start = ATS_get_cycles(); - #endif - for (i = 0; i < num_xstreams; i++) { -- ABT_thread_create(all_pools[i][0], test_fn, (void *)i, -+ ABT_thread_create(all_pools[i][0], test_fn, (void *)((uintptr_t)i), - ABT_THREAD_ATTR_NULL, &top_threads[i]); - } - for (i = 0; i < num_xstreams; i++) { From 29a3ad0747b4c70c1283dc9bc16def6ed560de2b Mon Sep 17 00:00:00 2001 From: Cedric Koch-Hofer Date: Fri, 23 Aug 2024 08:57:17 +0000 Subject: [PATCH 04/12] DAOS-15596 pkg: Update Argobots to 1.2 Fix source patching Signed-off-by: Cedric Koch-Hofer --- Makefile | 8 ++++++-- argobots.spec | 4 +++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index fe9b8209..d558cf20 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,8 @@ -NAME := argobots -SRC_EXT := gz +NAME := argobots +SRC_EXT := gz +PKG_GIT_COMMIT := 411e5b344642ebc82190fd8b125db512e5b449d1 +GITHUB_PROJECT := pmodels/$(NAME) +# This list of files that are in the upstream git repo but are not included in upstream's releases +# PATCH_EXCLUDE_FILES := include packaging/Makefile_packaging.mk diff --git a/argobots.spec b/argobots.spec index ac0155f8..32b67a91 100644 --- a/argobots.spec +++ b/argobots.spec @@ -11,8 +11,10 @@ Summary: Lightweight, low-level threading and tasking framework Group: System Environment/Libraries License: UChicago Argonne, LLC -- Argobots License Url: http://www.argobots.org/ -#Source: https://api.github.com/repos/pmodels/$(NAME)/tarball/31703b1 Source: https://github.com/pmodels/%{name}/releases/download/v%{tag}/%{name}-%{tag}.tar.gz +%if "%{?commit}" != "" +Patch0: %{version}..%{commit}.patch +%endif BuildRequires: pkgconfig From 69e02db79b6b5edc37cabb2d8167f68d7b18033c Mon Sep 17 00:00:00 2001 From: Cedric Koch-Hofer Date: Fri, 23 Aug 2024 08:57:17 +0000 Subject: [PATCH 05/12] DAOS-15596 pkg: Update Argobots to 1.2 Integrate reviewers comments. Signed-off-by: Cedric Koch-Hofer --- Makefile | 3 ++- argobots.spec | 4 +++- debian/changelog | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index d558cf20..4a1886d8 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,8 @@ NAME := argobots SRC_EXT := gz -PKG_GIT_COMMIT := 411e5b344642ebc82190fd8b125db512e5b449d1 GITHUB_PROJECT := pmodels/$(NAME) +# Patch commit ID to apply +# PKG_GIT_COMMIT := # This list of files that are in the upstream git repo but are not included in upstream's releases # PATCH_EXCLUDE_FILES := diff --git a/argobots.spec b/argobots.spec index 32b67a91..5de86255 100644 --- a/argobots.spec +++ b/argobots.spec @@ -15,6 +15,8 @@ Source: https://github.com/pmodels/%{name}/releases/download/v%{tag}/%{name}-%{t %if "%{?commit}" != "" Patch0: %{version}..%{commit}.patch %endif +# fix ULTs stacks dump works only once +Patch1: https://github.com/pmodels/argobots/commit/411e5b344642ebc82190fd8b125db512e5b449d1 BuildRequires: pkgconfig @@ -111,7 +113,7 @@ rm -f %{buildroot}%{_libdir}/*.{l,}a %doc README %changelog -* Tue Apr 02 2024 Brian J. Murrell - 1.2-1 +* Wed Sep 04 2024 Brian J. Murrell - 1.2-1 - Update to 1.2 - Add patch 411e5b3 fixing DAOS-14248 diff --git a/debian/changelog b/debian/changelog index 158fdb62..a6356c6d 100644 --- a/debian/changelog +++ b/debian/changelog @@ -3,7 +3,7 @@ argobots (1.2-1) unstable; urgency=medium * Update to 1.2 * Add patch 411e5b3 fixing DAOS-14248 - -- Brian J. Murrell Tue, 02 Apr 2024 16:08:44 -0400 + -- Brian J. Murrell Wed, 04 Sep 2024 16:08:44 -0400 argobots (1.1-2) unstable; urgency=medium [ Brian J. Murrell ] From 0e55bff620429fc6d3a8c8070435c5f1387dcf67 Mon Sep 17 00:00:00 2001 From: Cedric Koch-Hofer Date: Fri, 23 Aug 2024 08:57:17 +0000 Subject: [PATCH 06/12] DAOS-15596 pkg: Update Argobots to 1.2 Remove useless local patch Signed-off-by: Cedric Koch-Hofer --- ....411e5b344642ebc82190fd8b125db512e5b449d1.patch | 14 -------------- 1 file changed, 14 deletions(-) delete mode 100644 1.2..411e5b344642ebc82190fd8b125db512e5b449d1.patch diff --git a/1.2..411e5b344642ebc82190fd8b125db512e5b449d1.patch b/1.2..411e5b344642ebc82190fd8b125db512e5b449d1.patch deleted file mode 100644 index 2da6357f..00000000 --- a/1.2..411e5b344642ebc82190fd8b125db512e5b449d1.patch +++ /dev/null @@ -1,14 +0,0 @@ -diff --git a/src/info.c b/src/info.c -index 4127edf..5e5bb4b 100644 ---- a/src/info.c -+++ b/src/info.c -@@ -1097,7 +1097,8 @@ void ABTI_info_check_print_all_thread_stacks(void) - - /* Decrement the barrier value. */ - int dec_value = ABTD_atomic_fetch_sub_int(&print_stack_barrier, 1); -- if (dec_value == 0) { -+ /* previous value should be 1 ! */ -+ if (dec_value == 1) { - /* The last execution stream resets the flag. */ - ABTD_atomic_release_store_int(&print_stack_flag, - PRINT_STACK_FLAG_UNSET); From 8779a83c14d19c875800b4111f231bffe4f1d853 Mon Sep 17 00:00:00 2001 From: Cedric Koch-Hofer Date: Fri, 23 Aug 2024 08:57:17 +0000 Subject: [PATCH 07/12] DAOS-15596 pkg: Update Argobots to 1.2 Remove useless local patch management. Signed-off-by: Cedric Koch-Hofer --- Makefile | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index 4a1886d8..fe9b8209 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,4 @@ -NAME := argobots -SRC_EXT := gz -GITHUB_PROJECT := pmodels/$(NAME) -# Patch commit ID to apply -# PKG_GIT_COMMIT := -# This list of files that are in the upstream git repo but are not included in upstream's releases -# PATCH_EXCLUDE_FILES := +NAME := argobots +SRC_EXT := gz include packaging/Makefile_packaging.mk From ad39283628ee4c5afa34e468316d5928c243cfb9 Mon Sep 17 00:00:00 2001 From: Cedric Koch-Hofer Date: Fri, 23 Aug 2024 08:57:17 +0000 Subject: [PATCH 08/12] DAOS-15596 pkg: Update Argobots to 1.2 Fix invalid patch path. Signed-off-by: Cedric Koch-Hofer --- argobots.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/argobots.spec b/argobots.spec index 5de86255..439f8e7c 100644 --- a/argobots.spec +++ b/argobots.spec @@ -16,7 +16,7 @@ Source: https://github.com/pmodels/%{name}/releases/download/v%{tag}/%{name}-%{t Patch0: %{version}..%{commit}.patch %endif # fix ULTs stacks dump works only once -Patch1: https://github.com/pmodels/argobots/commit/411e5b344642ebc82190fd8b125db512e5b449d1 +Patch1: https://github.com/pmodels/argobots/commit/411e5b344642ebc82190fd8b125db512e5b449d1.patch BuildRequires: pkgconfig From 914b00bace0f9216619672518c8aa6459934886c Mon Sep 17 00:00:00 2001 From: Cedric Koch-Hofer Date: Fri, 23 Aug 2024 08:57:17 +0000 Subject: [PATCH 09/12] DAOS-15596 pkg: Update Argobots to 1.2 Add patch restoring libunwind support. Signed-off-by: Cedric Koch-Hofer --- argobots.spec | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/argobots.spec b/argobots.spec index 439f8e7c..5383c8ab 100644 --- a/argobots.spec +++ b/argobots.spec @@ -15,8 +15,10 @@ Source: https://github.com/pmodels/%{name}/releases/download/v%{tag}/%{name}-%{t %if "%{?commit}" != "" Patch0: %{version}..%{commit}.patch %endif -# fix ULTs stacks dump works only once +# Fix ULTs stacks dump works only once Patch1: https://github.com/pmodels/argobots/commit/411e5b344642ebc82190fd8b125db512e5b449d1.patch +# Restore the libunwind support +Patch2: https://github.com/pmodels/argobots/commit/bb0c908abfac4bfe37852eee621930634183c6aa.patch BuildRequires: pkgconfig From dbcdfee0000a4e1ad97f90e42965b16e07f8991f Mon Sep 17 00:00:00 2001 From: Cedric Koch-Hofer Date: Fri, 23 Aug 2024 08:57:17 +0000 Subject: [PATCH 10/12] DAOS-15596 pkg: Update Argobots to 1.2 Add configure option to enable check of configure step Signed-off-by: Cedric Koch-Hofer --- argobots.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/argobots.spec b/argobots.spec index 5383c8ab..9828ca9f 100644 --- a/argobots.spec +++ b/argobots.spec @@ -79,7 +79,7 @@ if true || [ ! -f configure ]; then ./autogen.sh fi # defaults: with-dlopen can be over-rode: -%configure --enable-valgrind --enable-stack-unwind +%configure --enable-valgrind --enable-stack-unwind --enable-option-checking=fatal make %{?_smp_mflags} V=1 %install From b740042afc6de291fe2d6165b91052417050165b Mon Sep 17 00:00:00 2001 From: Cedric Koch-Hofer Date: Fri, 23 Aug 2024 08:57:17 +0000 Subject: [PATCH 11/12] DAOS-15596 pkg: Update Argobots to 1.2 Integrate reviewers comments: - Add reference to the new patch bb0c908 fixing configuration issue - Update author and timestamp Signed-off-by: Cedric Koch-Hofer --- argobots.spec | 3 ++- debian/changelog | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/argobots.spec b/argobots.spec index 9828ca9f..147f3c24 100644 --- a/argobots.spec +++ b/argobots.spec @@ -115,9 +115,10 @@ rm -f %{buildroot}%{_libdir}/*.{l,}a %doc README %changelog -* Wed Sep 04 2024 Brian J. Murrell - 1.2-1 +* Wed Sep 25 2024 Cedric Koch-Hofer - 1.2-1 - Update to 1.2 - Add patch 411e5b3 fixing DAOS-14248 +- Add patch bb0c908 fixing libunwind support * Tue Jun 06 2023 Brian J. Murrell - 1.1-3 - Update to build on EL9 diff --git a/debian/changelog b/debian/changelog index a6356c6d..bbab71ce 100644 --- a/debian/changelog +++ b/debian/changelog @@ -2,8 +2,9 @@ argobots (1.2-1) unstable; urgency=medium [ Brian J. Murrell ] * Update to 1.2 * Add patch 411e5b3 fixing DAOS-14248 + * Add patch bb0c908 fixing libunwind support - -- Brian J. Murrell Wed, 04 Sep 2024 16:08:44 -0400 + -- Cedric Koch-Hofer Wed, 25 Sep 2024 16:08:44 -0500 argobots (1.1-2) unstable; urgency=medium [ Brian J. Murrell ] From ee7ba3f4579c71f97373dd1e5a0de76740ab83e5 Mon Sep 17 00:00:00 2001 From: Cedric Koch-Hofer Date: Fri, 23 Aug 2024 08:57:17 +0000 Subject: [PATCH 12/12] DAOS-15596 pkg: Update Argobots to 1.2 Integrate reviewers comments: - Harmonize documentation Signed-off-by: Cedric Koch-Hofer --- argobots.spec | 8 ++++---- debian/changelog | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/argobots.spec b/argobots.spec index 147f3c24..cc1b10d0 100644 --- a/argobots.spec +++ b/argobots.spec @@ -15,7 +15,7 @@ Source: https://github.com/pmodels/%{name}/releases/download/v%{tag}/%{name}-%{t %if "%{?commit}" != "" Patch0: %{version}..%{commit}.patch %endif -# Fix ULTs stacks dump works only once +# Fix DAOS-14248: ULTs stacks dump works only once Patch1: https://github.com/pmodels/argobots/commit/411e5b344642ebc82190fd8b125db512e5b449d1.patch # Restore the libunwind support Patch2: https://github.com/pmodels/argobots/commit/bb0c908abfac4bfe37852eee621930634183c6aa.patch @@ -115,10 +115,10 @@ rm -f %{buildroot}%{_libdir}/*.{l,}a %doc README %changelog -* Wed Sep 25 2024 Cedric Koch-Hofer - 1.2-1 +* Wed Oct 02 2024 Cedric Koch-Hofer - 1.2-1 - Update to 1.2 -- Add patch 411e5b3 fixing DAOS-14248 -- Add patch bb0c908 fixing libunwind support +- Add patch 411e5b3 Fix DAOS-14248: ULTs stacks dump works only once +- Add patch bb0c908 Restore the libunwind support * Tue Jun 06 2023 Brian J. Murrell - 1.1-3 - Update to build on EL9 diff --git a/debian/changelog b/debian/changelog index bbab71ce..93ad569b 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,10 +1,10 @@ argobots (1.2-1) unstable; urgency=medium - [ Brian J. Murrell ] + [ Cedric Koch-Hofer] * Update to 1.2 - * Add patch 411e5b3 fixing DAOS-14248 - * Add patch bb0c908 fixing libunwind support + * Add patch 411e5b3 Fix DAOS-14248: ULTs stacks dump works only once + * Add patch bb0c908 Restore the libunwind support - -- Cedric Koch-Hofer Wed, 25 Sep 2024 16:08:44 -0500 + -- Cedric Koch-Hofer Wed, 02 Oct 2024 16:08:44 -0500 argobots (1.1-2) unstable; urgency=medium [ Brian J. Murrell ]