Binary files /tmp/tmpt7sdqwfz/RMDthY72K3/r-cran-later-1.1.0.1+dfsg/build/vignette.rds and /tmp/tmpt7sdqwfz/ePb6SIq9iU/r-cran-later-1.3.0+dfsg/build/vignette.rds differ diff -Nru r-cran-later-1.1.0.1+dfsg/configure r-cran-later-1.3.0+dfsg/configure --- r-cran-later-1.1.0.1+dfsg/configure 2020-06-02 13:23:01.000000000 +0000 +++ r-cran-later-1.3.0+dfsg/configure 2021-08-18 14:03:28.000000000 +0000 @@ -20,9 +20,16 @@ EXTRA_PKG_LIBS=-latomic fi +case "$CC" in + *undefined*) + echo "Found UBSAN. Will skip tests that raise false positives." + PKG_CPPFLAGS="$PKG_CPPFLAGS -DUSING_UBSAN" + ;; +esac # Write to Makevars -sed -e "s|@extra_pkg_libs@|$EXTRA_PKG_LIBS|" src/Makevars.in > src/Makevars +sed -e "s|@extra_pkg_libs@|$EXTRA_PKG_LIBS|" -e "s|@pkg_cppflags@|$PKG_CPPFLAGS|" \ + src/Makevars.in > src/Makevars # Success exit 0 diff -Nru r-cran-later-1.1.0.1+dfsg/debian/changelog r-cran-later-1.3.0+dfsg/debian/changelog --- r-cran-later-1.1.0.1+dfsg/debian/changelog 2020-06-22 07:46:05.000000000 +0000 +++ r-cran-later-1.3.0+dfsg/debian/changelog 2021-09-21 04:40:35.000000000 +0000 @@ -1,3 +1,12 @@ +r-cran-later (1.3.0+dfsg-1) unstable; urgency=medium + + * New upstream version + * Standards-Version: 4.6.0 (routine-update) + * Set upstream metadata fields: Archive, Bug-Database, Bug-Submit, Repository, + Repository-Browse. + + -- Andreas Tille Tue, 21 Sep 2021 06:40:35 +0200 + r-cran-later (1.1.0.1+dfsg-1) unstable; urgency=medium * Team upload. diff -Nru r-cran-later-1.1.0.1+dfsg/debian/control r-cran-later-1.3.0+dfsg/debian/control --- r-cran-later-1.1.0.1+dfsg/debian/control 2020-06-22 07:46:05.000000000 +0000 +++ r-cran-later-1.3.0+dfsg/debian/control 2021-09-21 04:40:35.000000000 +0000 @@ -9,9 +9,8 @@ r-base-dev, r-cran-rcpp (>= 0.12.9), r-cran-rlang, - r-cran-bh, libboost-dev -Standards-Version: 4.5.0 +Standards-Version: 4.6.0 Vcs-Browser: https://salsa.debian.org/r-pkg-team/r-cran-later Vcs-Git: https://salsa.debian.org/r-pkg-team/r-cran-later.git Homepage: https://cran.r-project.org/package=later diff -Nru r-cran-later-1.1.0.1+dfsg/debian/upstream/metadata r-cran-later-1.3.0+dfsg/debian/upstream/metadata --- r-cran-later-1.1.0.1+dfsg/debian/upstream/metadata 1970-01-01 00:00:00.000000000 +0000 +++ r-cran-later-1.3.0+dfsg/debian/upstream/metadata 2021-09-21 04:40:35.000000000 +0000 @@ -0,0 +1,6 @@ +--- +Archive: CRAN +Bug-Database: https://github.com/r-lib/later/issues +Bug-Submit: https://github.com/r-lib/later/issues/new +Repository: https://github.com/r-lib/later.git +Repository-Browse: https://github.com/r-lib/later diff -Nru r-cran-later-1.1.0.1+dfsg/DESCRIPTION r-cran-later-1.3.0+dfsg/DESCRIPTION --- r-cran-later-1.1.0.1+dfsg/DESCRIPTION 2020-06-05 10:10:13.000000000 +0000 +++ r-cran-later-1.3.0+dfsg/DESCRIPTION 2021-08-18 16:30:06.000000000 +0000 @@ -2,11 +2,11 @@ Type: Package Title: Utilities for Scheduling Functions to Execute Later with Event Loops -Version: 1.1.0.1 +Version: 1.3.0 Authors@R: c( - person("Joe", "Cheng", role = c("aut", "cre"), email = "joe@rstudio.com"), + person("Winston", "Chang", role = c("aut", "cre"), email = "winston@rstudio.com"), + person("Joe", "Cheng", role = c("aut"), email = "joe@rstudio.com"), person(family = "RStudio", role = "cph"), - person("Winston", "Chang", role = c("aut"), email = "winston@rstudio.com"), person("Marcus", "Geelnard", role = c("ctb", "cph"), comment = "TinyCThread library, https://tinycthread.github.io/"), person("Evan", "Nemerson", role = c("ctb", "cph"), comment = "TinyCThread library, https://tinycthread.github.io/") ) @@ -15,21 +15,23 @@ in an event loop. URL: https://github.com/r-lib/later BugReports: https://github.com/r-lib/later/issues -License: GPL (>= 2) +License: MIT + file LICENSE Imports: Rcpp (>= 0.12.9), rlang -LinkingTo: Rcpp, BH -RoxygenNote: 7.1.0 -Suggests: knitr, rmarkdown, testthat +LinkingTo: Rcpp +RoxygenNote: 7.1.1 +SystemRequirements: C++11 +Suggests: knitr, rmarkdown, testthat (>= 2.1.0) VignetteBuilder: knitr +Encoding: UTF-8 NeedsCompilation: yes -Packaged: 2020-06-02 13:23:01 UTC; winston -Author: Joe Cheng [aut, cre], +Packaged: 2021-08-18 14:03:28 UTC; barret +Author: Winston Chang [aut, cre], + Joe Cheng [aut], RStudio [cph], - Winston Chang [aut], Marcus Geelnard [ctb, cph] (TinyCThread library, https://tinycthread.github.io/), Evan Nemerson [ctb, cph] (TinyCThread library, https://tinycthread.github.io/) -Maintainer: Joe Cheng +Maintainer: Winston Chang Repository: CRAN -Date/Publication: 2020-06-05 10:10:13 UTC +Date/Publication: 2021-08-18 16:30:06 UTC diff -Nru r-cran-later-1.1.0.1+dfsg/inst/include/later.h r-cran-later-1.3.0+dfsg/inst/include/later.h --- r-cran-later-1.1.0.1+dfsg/inst/include/later.h 2020-05-26 23:40:52.000000000 +0000 +++ r-cran-later-1.3.0+dfsg/inst/include/later.h 2021-08-17 20:05:55.000000000 +0000 @@ -3,7 +3,20 @@ #define _later_later_h #include -#include + +#ifndef R_NO_REMAP +#define R_NO_REMAP +#endif + +#ifndef STRICT_R_HEADERS +#define STRICT_R_HEADERS +#endif + +#include + +// Needed for R_GetCCallable on R 3.3 and older; in more recent versions, this +// is included via Rinternals.h. +#include #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN diff -Nru r-cran-later-1.1.0.1+dfsg/LICENSE r-cran-later-1.3.0+dfsg/LICENSE --- r-cran-later-1.1.0.1+dfsg/LICENSE 1970-01-01 00:00:00.000000000 +0000 +++ r-cran-later-1.3.0+dfsg/LICENSE 2021-08-17 20:05:55.000000000 +0000 @@ -0,0 +1,2 @@ +YEAR: 2020 +COPYRIGHT HOLDER: later authors diff -Nru r-cran-later-1.1.0.1+dfsg/MD5 r-cran-later-1.3.0+dfsg/MD5 --- r-cran-later-1.1.0.1+dfsg/MD5 2020-06-05 10:10:13.000000000 +0000 +++ r-cran-later-1.3.0+dfsg/MD5 2021-08-18 16:30:06.000000000 +0000 @@ -1,18 +1,19 @@ -9d8710998bad43567ffedfc772664cec *DESCRIPTION +f12200f33b13b85eaa73915cc68377ed *DESCRIPTION +1ea92efbfee0a5419e05c8bffb4d02d7 *LICENSE 0cc41b0056bcd20eabacbf9459223b54 *LICENSE.note 9b44c74bf9bd7267cf31f8bd44cdc933 *NAMESPACE -28ee80fac687d7f20d3c7953164a8acc *NEWS.md -ff1d590746700bb7d5f09b76037cc1e2 *R/RcppExports.R +bf91ba36d4933788db321d94bccf77de *NEWS.md +0fa4fa3ec1e07bdf2fc2e4b244f3f3da *R/RcppExports.R ed3c7ae2148e29b8839502954bf559b0 *R/debug.R fc698c01f5602d68b4d1be2ddc4fcecb *R/later.R -1c93ccf9bceb48d1d1345b5d5fad6bab *README.md -8f175c13d54403e97f0725934b862f89 *build/vignette.rds +61db794e43661d5a11f248094f543b70 *README.md +496c3f00f9a8c4b5f51ce2df91a38e34 *build/vignette.rds 6071edd604dbeb75308cfbedc7790398 *cleanup -5888b3a12af975d993a762e743a7374a *configure +793c150da12198c9c0a2c8e5811e721d *configure c37ad0d619d6d8eceb3fd7628b145b68 *inst/bgtest.cpp 88133661f44a9f8a51e06a1d8b044372 *inst/doc/later-cpp.Rmd -13c63990a6a70f3686628b97d89ee68b *inst/doc/later-cpp.html -49d6fbcdc3356a98b88250e7bacccbb3 *inst/include/later.h +897d314bcfd449a01d0693a0be5fd218 *inst/doc/later-cpp.html +bf0655e9a630d3f3fc4beaa9b30e454e *inst/include/later.h 9a4fb9c64c2be8f09b461fc8cb63b25b *inst/include/later_api.h f6132a7bbcc21d7a05298c7bad6a46ca *man/create_loop.Rd c7a4ed3341b448160cde2b39223e36f5 *man/later.Rd @@ -21,28 +22,28 @@ 59c1460cee99ddb482be8282b8dbe77e *man/loop_empty.Rd ec0cae09be3f35707cc4fc3ca48bf549 *man/next_op_secs.Rd 9a4ca52d98ce2ff6e811c6ab368e00ba *man/run_now.Rd -8f167e9daf596b84947ddfa6e73d94b8 *src/Makevars.in +9dbb6a73ce7e9097f83888b09946dcd8 *src/Makevars.in c8e20603005445497b9630c706155981 *src/Makevars.win -f9f9fbfe954e6296fba02a9ee1437c71 *src/RcppExports.cpp +df230a1f08a7f364e490adcff5eab03c *src/RcppExports.cpp 231720fa3615e4cd3bc50faf2a486628 *src/badthreads.h -ba480ae55b2973d08c36270bbbed41c1 *src/callback_registry.cpp -eeb69f04b0ddad2bb2c290ea6f74fec9 *src/callback_registry.h -dd5029ada4898f39ee64b516924bb82a *src/callback_registry_table.h -ba4cad5dcfd74355cf708bf17af135ee *src/debug.cpp +e8f9a5c0e9e133af1535a0cec1518123 *src/callback_registry.cpp +1b9436e681ac616bb696f63b6e98d043 *src/callback_registry.h +c103f87b9273d795462956a63e361655 *src/callback_registry_table.h +8465cb8bd54cb837c237ddcae881368b *src/debug.cpp 85df09c6674a89ced0a381d0f7db2f6e *src/debug.h -660c904d6c5b05b01a2f2fc6c82701c7 *src/init.c +3d7e4b74b9edff227b63373501c4ae36 *src/init.c 56792fc6e11c596d958add3d2ce86743 *src/interrupt.h -91b2dab255d946760cc7eb9a5a7cdf4d *src/later.cpp -fb49b34e5c615514cd33963b94a8e1ad *src/later.h -a7e3b64f54dd04afcf4af7961fc7afc4 *src/later_posix.cpp -bf937542819523dca5ebb663f3551b2e *src/later_win32.cpp -85a4f04613e7ce81d7f4e16d2e8dad01 *src/optional.h -7b62ded82d05640c891d116c67d34d0c *src/threadutils.h +972e2622ccc67bd43964675cdcbdd860 *src/later.cpp +28ad43027f7342ad53e46285979d63ad *src/later.h +d29a61f518d28b05d9f8086713c2d2f7 *src/later_posix.cpp +aabbec9c26b84a74781089db9ffb3f27 *src/later_win32.cpp +08957a476d21528caa9d160f2c7b1159 *src/optional.h +5e54700f876489f0e6e2420fda4f29d5 *src/threadutils.h 534cc709ed5b410d281d04e7682372d0 *src/timeconv.h -d534b980679c0dadeb9475fc4c2bdb79 *src/timer_posix.cpp -266032cf8c0486134061931d71045cee *src/timer_posix.h -297702ee6720fd0e033b9d981149d9a3 *src/timestamp.h -0a46800cc07bbefe505e122465f67ea8 *src/timestamp_unix.cpp +e2afcd8a068f5f116893c31ee06488bf *src/timer_posix.cpp +0a5fdb0bd7f687c614abf43695451fcc *src/timer_posix.h +cb393170bd1af018865d33b3f92bb59d *src/timestamp.h +755882a4df5a84994690bd03d5da9303 *src/timestamp_unix.cpp b4b60c05ed6b7f2ede8310aedc24a23a *src/timestamp_win32.cpp f432ea392a438da68d87978c0d712b40 *src/tinycthread.c ad56b217c12e12792e86edc5617b082c *src/tinycthread.h @@ -51,5 +52,5 @@ c3e5ee58b5d7e1e4c89c82a02b19287c *tests/testthat/test-c-api.R c75627b4bc39c2b3589483afaeab5d52 *tests/testthat/test-cancel.R 31d99373415fe244392d30b2207337b7 *tests/testthat/test-private-loops.R -5be3ebb058f59213d52e1984d5c8cbc9 *tests/testthat/test-run_now.R +609f9b2bb8fa0fc4cae0ed3e932eab02 *tests/testthat/test-run_now.R 88133661f44a9f8a51e06a1d8b044372 *vignettes/later-cpp.Rmd diff -Nru r-cran-later-1.1.0.1+dfsg/NEWS.md r-cran-later-1.3.0+dfsg/NEWS.md --- r-cran-later-1.1.0.1+dfsg/NEWS.md 2020-06-02 13:22:39.000000000 +0000 +++ r-cran-later-1.3.0+dfsg/NEWS.md 2021-08-17 20:10:02.000000000 +0000 @@ -1,3 +1,19 @@ +# later 1.3.0 + +* Closed #148: When later was attached, `parallel::makeForkCluster()` would fail. (#149) + +* Fixed #150: It was possible for callbacks to execute in the wrong order if the clock time was changed in between the scheduling of two callbacks. (#151) + +## later 1.2.0 + +* Closed #138: later is now licensed as MIT. (#139) + +* Closed #140: Previously, the event loop stopped running if the R process was forked. (#141) + +* Closed #143: Packages which link to later no longer need to take a direct dependency on Rcpp, because `later.h` no longer includes `Rcpp.h`. (#144) + +* Removed dependency on the BH package. C++11 is now required. (#147) + ## later 1.1.0.1 * Private event loops are now automatically run by their parent. That is, whenever an event loop is run, its children event loops are automatically run. The `create_loop()` function has a new parameter `parent`, which defaults to the current loop. The auto-running behavior can be disabled by using `create_loop(parent=NULL)`. (#119) diff -Nru r-cran-later-1.1.0.1+dfsg/R/RcppExports.R r-cran-later-1.3.0+dfsg/R/RcppExports.R --- r-cran-later-1.1.0.1+dfsg/R/RcppExports.R 2020-05-26 23:40:52.000000000 +0000 +++ r-cran-later-1.3.0+dfsg/R/RcppExports.R 2021-08-17 20:11:27.000000000 +0000 @@ -9,6 +9,10 @@ .Call('_later_log_level', PACKAGE = 'later', level) } +using_ubsan <- function() { + .Call('_later_using_ubsan', PACKAGE = 'later') +} + setCurrentRegistryId <- function(id) { invisible(.Call('_later_setCurrentRegistryId', PACKAGE = 'later', id)) } diff -Nru r-cran-later-1.1.0.1+dfsg/README.md r-cran-later-1.3.0+dfsg/README.md --- r-cran-later-1.1.0.1+dfsg/README.md 2019-09-27 17:34:26.000000000 +0000 +++ r-cran-later-1.3.0+dfsg/README.md 2021-08-17 20:05:54.000000000 +0000 @@ -1,8 +1,7 @@ # later -[![Build Status](https://travis-ci.org/r-lib/later.svg?branch=master)](https://travis-ci.org/r-lib/later) -[![AppVeyor build status](https://ci.appveyor.com/api/projects/status/github/r-lib/later?branch=master&svg=true)](https://ci.appveyor.com/project/r-lib/later) +[![R build status](https://github.com/r-lib/later/workflows/R-CMD-check/badge.svg)](https://github.com/r-lib/later/actions) @@ -59,7 +58,7 @@ BackgroundTask(); virtual ~BackgroundTask(); - // Start executing the task + // Start executing the task void begin(); protected: @@ -69,7 +68,7 @@ // to be passed into or out of the Execute method must be // included as fields on the Task subclass object. virtual void execute() = 0; - + // A short task that runs on the main R thread after the // background task has completed. It's safe to access the // R runtime and R data structures from here. @@ -97,12 +96,12 @@ for (std::vector::const_iterator it = inputVals.begin(); it != inputVals.end(); it++) { - + sum += *it; } result = sum / inputVals.size(); } - + void complete() { Rprintf("Result is %f\n", result); } diff -Nru r-cran-later-1.1.0.1+dfsg/src/callback_registry.cpp r-cran-later-1.3.0+dfsg/src/callback_registry.cpp --- r-cran-later-1.1.0.1+dfsg/src/callback_registry.cpp 2020-05-26 23:40:52.000000000 +0000 +++ r-cran-later-1.3.0+dfsg/src/callback_registry.cpp 2021-08-17 20:05:55.000000000 +0000 @@ -1,21 +1,12 @@ -#include -#include -#include +#include +#include +#include #include + #include "callback_registry.h" #include "debug.h" -#if __cplusplus >= 201103L - #include - std::atomic nextCallbackId(1); -#else - // Fall back to boost::atomic if std::atomic isn't available. We want to - // avoid boost::atomic when possible because on ARM, it requires the - // -lboost_atomic linker flag. (https://github.com/r-lib/later/issues/73) - #include - boost::atomic nextCallbackId(1); -#endif - +std::atomic nextCallbackId(1); // ============================================================================ // Invoke functions @@ -50,7 +41,7 @@ // interrupt or an R error, it will throw a C++ exception. These exceptions // are the ones defined by Rcpp, and they will be caught by the try-catch in // this function. -// * It could be a BoostFunctionCallback with C or C++ code. +// * It could be a StdFunctionCallback with C or C++ code. // * If the function invokes an Rcpp::Function and an interrupt or R error // happens within the Rcpp::Function, it will throw exceptions just like // the RcppFunctionCallback case, and they will be caught. @@ -174,17 +165,17 @@ // ============================================================================ -// BoostFunctionCallback +// StdFunctionCallback // ============================================================================ -BoostFunctionCallback::BoostFunctionCallback(Timestamp when, boost::function func) : +StdFunctionCallback::StdFunctionCallback(Timestamp when, std::function func) : Callback(when), func(func) { this->callbackId = nextCallbackId++; } -Rcpp::RObject BoostFunctionCallback::rRepresentation() const { +Rcpp::RObject StdFunctionCallback::rRepresentation() const { using namespace Rcpp; ASSERT_MAIN_THREAD() @@ -226,11 +217,11 @@ // [[Rcpp::export]] void testCallbackOrdering() { - std::vector callbacks; + std::vector callbacks; Timestamp ts; - boost::function func; + std::function func; for (size_t i = 0; i < 100; i++) { - callbacks.push_back(BoostFunctionCallback(ts, func)); + callbacks.push_back(StdFunctionCallback(ts, func)); } for (size_t i = 1; i < 100; i++) { if (callbacks[i] < callbacks[i-1]) { @@ -271,7 +262,7 @@ // Copies of the Rcpp::Function should only be made on the main thread. ASSERT_MAIN_THREAD() Timestamp when(secs); - Callback_sp cb = boost::make_shared(when, func); + Callback_sp cb = std::make_shared(when, func); Guard guard(mutex); queue.insert(cb); condvar->signal(); @@ -281,7 +272,7 @@ uint64_t CallbackRegistry::add(void (*func)(void*), void* data, double secs) { Timestamp when(secs); - Callback_sp cb = boost::make_shared(when, boost::bind(func, data)); + Callback_sp cb = std::make_shared(when, std::bind(func, data)); Guard guard(mutex); queue.insert(cb); condvar->signal(); @@ -317,7 +308,7 @@ // Now check children if (recursive) { - for (std::vector >::const_iterator it = children.begin(); + for (std::vector >::const_iterator it = children.begin(); it != children.end(); ++it) { @@ -354,7 +345,7 @@ // Now check children if (recursive) { - for (std::vector >::const_iterator it = children.begin(); + for (std::vector >::const_iterator it = children.begin(); it != children.end(); ++it) { diff -Nru r-cran-later-1.1.0.1+dfsg/src/callback_registry.h r-cran-later-1.3.0+dfsg/src/callback_registry.h --- r-cran-later-1.1.0.1+dfsg/src/callback_registry.h 2020-05-26 23:40:52.000000000 +0000 +++ r-cran-later-1.3.0+dfsg/src/callback_registry.h 2021-08-17 20:05:55.000000000 +0000 @@ -3,15 +3,14 @@ #include #include -#include -#include -#include +#include +#include #include "timestamp.h" #include "optional.h" #include "threadutils.h" // Callback is an abstract class with two subclasses. The reason that there -// are two subclasses is because one of them is for C++ (boost::function) +// are two subclasses is because one of them is for C++ (std::function) // callbacks, and the other is for R (Rcpp::Function) callbacks. Because // Callbacks can be created from either the main thread or a background // thread, the top-level Callback class cannot contain any Rcpp objects -- @@ -52,9 +51,9 @@ }; -class BoostFunctionCallback : public Callback { +class StdFunctionCallback : public Callback { public: - BoostFunctionCallback(Timestamp when, boost::function func); + StdFunctionCallback(Timestamp when, std::function func); void invoke() const { func(); @@ -63,7 +62,7 @@ Rcpp::RObject rRepresentation() const; private: - boost::function func; + std::function func; }; @@ -83,7 +82,7 @@ -typedef boost::shared_ptr Callback_sp; +typedef std::shared_ptr Callback_sp; template struct pointer_less_than { @@ -153,8 +152,8 @@ // References to parent and children registries. These are used for // automatically running child loops. They should only be accessed and // modified from the main thread. - boost::shared_ptr parent; - std::vector > children; + std::shared_ptr parent; + std::vector > children; }; #endif // _CALLBACK_REGISTRY_H_ diff -Nru r-cran-later-1.1.0.1+dfsg/src/callback_registry_table.h r-cran-later-1.3.0+dfsg/src/callback_registry_table.h --- r-cran-later-1.1.0.1+dfsg/src/callback_registry_table.h 2020-05-26 23:40:52.000000000 +0000 +++ r-cran-later-1.3.0+dfsg/src/callback_registry_table.h 2021-08-17 20:05:55.000000000 +0000 @@ -2,15 +2,14 @@ #define _CALLBACK_REGISTRY_TABLE_H_ #include -#include -#include +#include #include "threadutils.h" #include "debug.h" #include "callback_registry.h" #include "later.h" -using boost::shared_ptr; -using boost::make_shared; +using std::shared_ptr; +using std::make_shared; // ============================================================================ // Callback registry table @@ -30,14 +29,14 @@ // object references it. class RegistryHandle { public: - RegistryHandle(boost::shared_ptr registry, bool r_ref_exists) + RegistryHandle(std::shared_ptr registry, bool r_ref_exists) : registry(registry), r_ref_exists(r_ref_exists) { }; // Need to declare a copy constructor. Needed because pre-C++11 std::map // doesn't have an .emplace() method. RegistryHandle() = default; - boost::shared_ptr registry; + std::shared_ptr registry; bool r_ref_exists; }; @@ -200,7 +199,7 @@ } // Tell the children that they no longer have a parent. - for (std::vector >::iterator it = registry->children.begin(); + for (std::vector >::iterator it = registry->children.begin(); it != registry->children.end(); ++it) { diff -Nru r-cran-later-1.1.0.1+dfsg/src/debug.cpp r-cran-later-1.3.0+dfsg/src/debug.cpp --- r-cran-later-1.1.0.1+dfsg/src/debug.cpp 2020-05-26 23:40:52.000000000 +0000 +++ r-cran-later-1.3.0+dfsg/src/debug.cpp 2021-08-17 20:05:55.000000000 +0000 @@ -68,3 +68,13 @@ default: return ""; } } + +// Reports whether package was compiled with UBSAN +// [[Rcpp::export]] +bool using_ubsan() { +#ifdef USING_UBSAN + return true; +#else + return false; +#endif +} diff -Nru r-cran-later-1.1.0.1+dfsg/src/init.c r-cran-later-1.3.0+dfsg/src/init.c --- r-cran-later-1.1.0.1+dfsg/src/init.c 2020-05-26 23:40:52.000000000 +0000 +++ r-cran-later-1.3.0+dfsg/src/init.c 2021-08-17 20:05:55.000000000 +0000 @@ -24,6 +24,7 @@ extern SEXP _later_getCurrentRegistryId(); extern SEXP _later_list_queue_(SEXP); extern SEXP _later_log_level(SEXP); +extern SEXP _later_using_ubsan(); static const R_CallMethodDef CallEntries[] = { {"_later_ensureInitialized", (DL_FUNC) &_later_ensureInitialized, 0}, @@ -37,10 +38,11 @@ {"_later_deleteCallbackRegistry", (DL_FUNC) &_later_deleteCallbackRegistry, 1}, {"_later_existsCallbackRegistry", (DL_FUNC) &_later_existsCallbackRegistry, 1}, {"_later_notifyRRefDeleted", (DL_FUNC) &_later_notifyRRefDeleted, 1}, - {"_later_setCurrentRegistryId", (DL_FUNC) &_later_setCurrentRegistryId, 1}, - {"_later_getCurrentRegistryId", (DL_FUNC) &_later_getCurrentRegistryId, 0}, + {"_later_setCurrentRegistryId", (DL_FUNC) &_later_setCurrentRegistryId, 1}, + {"_later_getCurrentRegistryId", (DL_FUNC) &_later_getCurrentRegistryId, 0}, {"_later_list_queue_", (DL_FUNC) &_later_list_queue_, 1}, {"_later_log_level", (DL_FUNC) &_later_log_level, 1}, + {"_later_using_ubsan", (DL_FUNC) &_later_using_ubsan, 0}, {NULL, NULL, 0} }; diff -Nru r-cran-later-1.1.0.1+dfsg/src/later.cpp r-cran-later-1.3.0+dfsg/src/later.cpp --- r-cran-later-1.1.0.1+dfsg/src/later.cpp 2020-05-26 23:40:52.000000000 +0000 +++ r-cran-later-1.3.0+dfsg/src/later.cpp 2021-08-17 20:05:55.000000000 +0000 @@ -2,9 +2,7 @@ #include #include #include -#include -#include -#include +#include #include "debug.h" #include "utils.h" #include "threadutils.h" @@ -14,7 +12,7 @@ #include "interrupt.h" -using boost::shared_ptr; +using std::shared_ptr; static size_t exec_callbacks_reentrancy_count = 0; @@ -212,8 +210,8 @@ // I think there's no need to lock this since it's only modified from the // main thread. But need to check. - std::vector > children = callback_registry->children; - for (std::vector >::iterator it = children.begin(); + std::vector > children = callback_registry->children; + for (std::vector >::iterator it = children.begin(); it != children.end(); ++it) { diff -Nru r-cran-later-1.1.0.1+dfsg/src/later.h r-cran-later-1.3.0+dfsg/src/later.h --- r-cran-later-1.1.0.1+dfsg/src/later.h 2020-05-26 23:40:52.000000000 +0000 +++ r-cran-later-1.3.0+dfsg/src/later.h 2021-08-17 20:05:55.000000000 +0000 @@ -2,7 +2,7 @@ #define _LATER_H_ #include -#include +#include #include "callback_registry.h" // This should be kept in sync with LATER_H_API_VERSION in @@ -12,7 +12,7 @@ #define GLOBAL_LOOP 0 -boost::shared_ptr getGlobalRegistry(); +std::shared_ptr getGlobalRegistry(); bool execCallbacksForTopLevel(); bool at_top_level(); @@ -29,7 +29,7 @@ // and later_win32.cpp. void ensureAutorunnerInitialized(); -uint64_t doExecLater(boost::shared_ptr callbackRegistry, Rcpp::Function callback, double delaySecs, bool resetTimer); -uint64_t doExecLater(boost::shared_ptr callbackRegistry, void (*callback)(void*), void* data, double delaySecs, bool resetTimer); +uint64_t doExecLater(std::shared_ptr callbackRegistry, Rcpp::Function callback, double delaySecs, bool resetTimer); +uint64_t doExecLater(std::shared_ptr callbackRegistry, void (*callback)(void*), void* data, double delaySecs, bool resetTimer); #endif // _LATER_H_ diff -Nru r-cran-later-1.1.0.1+dfsg/src/later_posix.cpp r-cran-later-1.3.0+dfsg/src/later_posix.cpp --- r-cran-later-1.1.0.1+dfsg/src/later_posix.cpp 2020-05-26 23:40:52.000000000 +0000 +++ r-cran-later-1.3.0+dfsg/src/later_posix.cpp 2021-08-17 20:05:55.000000000 +0000 @@ -26,9 +26,11 @@ // The handles to the read and write ends of a pipe. We use this pipe // to signal R's input handler callback mechanism that we want to be // called back. -int pipe_in, pipe_out; +int pipe_in = -1; +int pipe_out = -1; -int dummy_pipe_in, dummy_pipe_out; +int dummy_pipe_in = -1; +int dummy_pipe_out = -1; // Whether the file descriptor is ready for reading, i.e., whether // the input handler callback is scheduled to be called. We use this @@ -147,8 +149,43 @@ static void remove_dummy_handler(void *data) { ASSERT_MAIN_THREAD() removeInputHandler(&R_InputHandlers, dummyInputHandlerHandle); - close(dummy_pipe_in); - close(dummy_pipe_out); + if (dummy_pipe_in > 0) { + close(dummy_pipe_in); + dummy_pipe_in = -1; + } + if (dummy_pipe_out > 0) { + close(dummy_pipe_out); + dummy_pipe_out = -1; + } +} + +// Callback to run in child process after forking. +void child_proc_after_fork() { + ASSERT_MAIN_THREAD() + if (initialized) { + removeInputHandler(&R_InputHandlers, inputHandlerHandle); + + if (pipe_in > 0) { + close(pipe_in); + pipe_in = -1; + } + if (pipe_out > 0) { + close(pipe_out); + pipe_out = -1; + } + + removeInputHandler(&R_InputHandlers, dummyInputHandlerHandle); + if (dummy_pipe_in > 0) { + close(dummy_pipe_in); + dummy_pipe_in = -1; + } + if (dummy_pipe_out > 0) { + close(dummy_pipe_out); + dummy_pipe_out = -1; + } + + initialized = 0; + } } void ensureAutorunnerInitialized() { @@ -166,6 +203,15 @@ inputHandlerHandle = addInputHandler(R_InputHandlers, pipe_out, async_input_handler, LATER_ACTIVITY); + // If the R process is forked, make sure that the child process doesn't mess + // with the pipes. This also means that functions scheduled in the child + // process with `later()` will only work if `run_now()` is called. In this + // situation, there's also the danger that a function will be scheduled by + // the parent process and then will be executed in the child process (in + // addition to in the parent process). + // https://github.com/r-lib/later/issues/140 + pthread_atfork(NULL, NULL, child_proc_after_fork); + // Need to add a dummy input handler to avoid segfault when the "real" // input handler removes the subsequent input handler in the linked list. // See https://github.com/rstudio/httpuv/issues/78 @@ -186,8 +232,14 @@ ASSERT_MAIN_THREAD() if (initialized) { removeInputHandler(&R_InputHandlers, inputHandlerHandle); - close(pipe_in); - close(pipe_out); + if (pipe_in > 0) { + close(pipe_in); + pipe_in = -1; + } + if (pipe_out > 0) { + close(pipe_out); + pipe_out = -1; + } initialized = 0; // Trigger remove_dummy_handler() @@ -196,7 +248,7 @@ } } -uint64_t doExecLater(boost::shared_ptr callbackRegistry, Rcpp::Function callback, double delaySecs, bool resetTimer) { +uint64_t doExecLater(std::shared_ptr callbackRegistry, Rcpp::Function callback, double delaySecs, bool resetTimer) { ASSERT_MAIN_THREAD() uint64_t callback_id = callbackRegistry->add(callback, delaySecs); @@ -210,7 +262,7 @@ return callback_id; } -uint64_t doExecLater(boost::shared_ptr callbackRegistry, void (*callback)(void*), void* data, double delaySecs, bool resetTimer) { +uint64_t doExecLater(std::shared_ptr callbackRegistry, void (*callback)(void*), void* data, double delaySecs, bool resetTimer) { uint64_t callback_id = callbackRegistry->add(callback, data, delaySecs); if (resetTimer) diff -Nru r-cran-later-1.1.0.1+dfsg/src/later_win32.cpp r-cran-later-1.3.0+dfsg/src/later_win32.cpp --- r-cran-later-1.1.0.1+dfsg/src/later_win32.cpp 2020-05-26 23:40:52.000000000 +0000 +++ r-cran-later-1.3.0+dfsg/src/later_win32.cpp 2021-08-17 20:05:55.000000000 +0000 @@ -101,7 +101,7 @@ } } -uint64_t doExecLater(boost::shared_ptr callbackRegistry, Rcpp::Function callback, double delaySecs, bool resetTimer) { +uint64_t doExecLater(std::shared_ptr callbackRegistry, Rcpp::Function callback, double delaySecs, bool resetTimer) { uint64_t callback_id = callbackRegistry->add(callback, delaySecs); if (resetTimer) @@ -110,7 +110,7 @@ return callback_id; } -uint64_t doExecLater(boost::shared_ptr callbackRegistry, void (*func)(void*), void* data, double delaySecs, bool resetTimer) { +uint64_t doExecLater(std::shared_ptr callbackRegistry, void (*func)(void*), void* data, double delaySecs, bool resetTimer) { uint64_t callback_id = callbackRegistry->add(func, data, delaySecs); if (resetTimer) { diff -Nru r-cran-later-1.1.0.1+dfsg/src/Makevars.in r-cran-later-1.3.0+dfsg/src/Makevars.in --- r-cran-later-1.1.0.1+dfsg/src/Makevars.in 2020-05-26 23:40:52.000000000 +0000 +++ r-cran-later-1.3.0+dfsg/src/Makevars.in 2021-08-17 20:05:55.000000000 +0000 @@ -1,7 +1,7 @@ # Use C++11 if available CXX_STD=CXX11 -PKG_CPPFLAGS = -pthread -DSTRICT_R_HEADERS +PKG_CPPFLAGS = -pthread -DSTRICT_R_HEADERS @pkg_cppflags@ PKG_LIBS = -pthread @extra_pkg_libs@ #### Debugging flags #### diff -Nru r-cran-later-1.1.0.1+dfsg/src/optional.h r-cran-later-1.3.0+dfsg/src/optional.h --- r-cran-later-1.1.0.1+dfsg/src/optional.h 2019-09-27 17:34:26.000000000 +0000 +++ r-cran-later-1.3.0+dfsg/src/optional.h 2021-08-17 20:05:55.000000000 +0000 @@ -5,14 +5,14 @@ class Optional { bool has; T value; - + public: Optional() : has(false), value() { } - + Optional(const T& val) : has(true), value(val) { } - + const T& operator*() const { return this->value; } @@ -22,10 +22,23 @@ T* operator->() { return &this->value; } - + void operator=(const T& value) { + this->value = value; + this->has = true; + } + bool has_value() const { return has; } + + void reset() { + // Creating a new object may be problematic or expensive for some classes; + // however, for the types we use in later, this is OK. If Optional is used + // for more types in the future, we could switch to a different + // implementation of optional. + this->value = T(); + this->has= false; + } }; #endif // _OPTIONAL_H_ diff -Nru r-cran-later-1.1.0.1+dfsg/src/RcppExports.cpp r-cran-later-1.3.0+dfsg/src/RcppExports.cpp --- r-cran-later-1.1.0.1+dfsg/src/RcppExports.cpp 2020-05-26 23:40:52.000000000 +0000 +++ r-cran-later-1.3.0+dfsg/src/RcppExports.cpp 2021-08-17 20:11:27.000000000 +0000 @@ -6,6 +6,11 @@ using namespace Rcpp; +#ifdef RCPP_USE_GLOBAL_ROSTREAM +Rcpp::Rostream& Rcpp::Rcout = Rcpp::Rcpp_cout_get(); +Rcpp::Rostream& Rcpp::Rcerr = Rcpp::Rcpp_cerr_get(); +#endif + // testCallbackOrdering void testCallbackOrdering(); RcppExport SEXP _later_testCallbackOrdering() { @@ -26,6 +31,16 @@ return rcpp_result_gen; END_RCPP } +// using_ubsan +bool using_ubsan(); +RcppExport SEXP _later_using_ubsan() { +BEGIN_RCPP + Rcpp::RObject rcpp_result_gen; + Rcpp::RNGScope rcpp_rngScope_gen; + rcpp_result_gen = Rcpp::wrap(using_ubsan()); + return rcpp_result_gen; +END_RCPP +} // setCurrentRegistryId void setCurrentRegistryId(int id); RcppExport SEXP _later_setCurrentRegistryId(SEXP idSEXP) { diff -Nru r-cran-later-1.1.0.1+dfsg/src/threadutils.h r-cran-later-1.3.0+dfsg/src/threadutils.h --- r-cran-later-1.1.0.1+dfsg/src/threadutils.h 2020-05-26 23:40:52.000000000 +0000 +++ r-cran-later-1.3.0+dfsg/src/threadutils.h 2021-08-17 20:05:55.000000000 +0000 @@ -3,16 +3,14 @@ #include #include -#include -#include -#include +#include #include "tinycthread.h" #include "timeconv.h" class ConditionVariable; -class Mutex : boost::noncopyable { +class Mutex { friend class ConditionVariable; tct_mtx_t _m; @@ -33,6 +31,10 @@ } } + // Make non-copyable + Mutex(const Mutex&) = delete; + Mutex& operator=(const Mutex&) = delete; + virtual ~Mutex() { tct_mtx_destroy(&_m); } @@ -61,7 +63,7 @@ } }; -class Guard : boost::noncopyable { +class Guard { Mutex* _mutex; public: @@ -69,12 +71,16 @@ _mutex->lock(); } + // Make non-copyable + Guard(const Guard&) = delete; + Guard& operator=(const Guard&) = delete; + ~Guard() { _mutex->unlock(); } }; -class ConditionVariable : boost::noncopyable { +class ConditionVariable { tct_mtx_t* _m; tct_cnd_t _c; @@ -82,17 +88,21 @@ ConditionVariable(Mutex& mutex) : _m(&mutex._m) { // If time_t isn't integral, our addSeconds logic needs to change, // as it relies on casting to time_t being a truncation. - if (!boost::is_integral::value) + if (!std::is_integral::value) throw std::runtime_error("Integral time_t type expected"); // If time_t isn't signed, our addSeconds logic can't handle // negative values for secs. - if (!boost::is_signed::value) + if (!std::is_signed::value) throw std::runtime_error("Signed time_t type expected"); if (tct_cnd_init(&_c) != tct_thrd_success) throw std::runtime_error("Condition variable failed to initialize"); } + // Make non-copyable + ConditionVariable(const ConditionVariable&) = delete; + ConditionVariable& operator=(const ConditionVariable&) = delete; + virtual ~ConditionVariable() { tct_cnd_destroy(&_c); } diff -Nru r-cran-later-1.1.0.1+dfsg/src/timer_posix.cpp r-cran-later-1.3.0+dfsg/src/timer_posix.cpp --- r-cran-later-1.1.0.1+dfsg/src/timer_posix.cpp 2020-05-26 23:40:52.000000000 +0000 +++ r-cran-later-1.3.0+dfsg/src/timer_posix.cpp 2021-08-17 20:05:55.000000000 +0000 @@ -16,7 +16,7 @@ // Guarded wait; we can't pass here until either the timer is stopped or we // have a wait time. - while (!(this->stopped || this->wakeAt != boost::none)) { + while (!(this->stopped || this->wakeAt.has_value())) { this->cond.wait(); } @@ -42,12 +42,12 @@ } } - this->wakeAt = boost::none; + this->wakeAt.reset(); callback(); } } -Timer::Timer(const boost::function& callback) : +Timer::Timer(const std::function& callback) : callback(callback), mutex(tct_mtx_recursive), cond(mutex), stopped(false) { } @@ -56,7 +56,7 @@ // Must stop background thread before cleaning up condition variable and // mutex. Calling pthread_cond_destroy on a condvar that's being waited // on results in undefined behavior--on Fedora 25+ it hangs. - if (this->bgthread != boost::none) { + if (this->bgthread.has_value()) { { Guard guard(&this->mutex); this->stopped = true; @@ -71,7 +71,7 @@ Guard guard(&this->mutex); // If the thread has not yet been created, created it. - if (this->bgthread == boost::none) { + if (!this->bgthread.has_value()) { tct_thrd_t thread; tct_thrd_create(&thread, &bg_main_func, this); this->bgthread = thread; diff -Nru r-cran-later-1.1.0.1+dfsg/src/timer_posix.h r-cran-later-1.3.0+dfsg/src/timer_posix.h --- r-cran-later-1.1.0.1+dfsg/src/timer_posix.h 2020-05-26 23:40:52.000000000 +0000 +++ r-cran-later-1.3.0+dfsg/src/timer_posix.h 2021-08-17 20:05:55.000000000 +0000 @@ -3,26 +3,26 @@ #ifndef _WIN32 -#include -#include +#include #include "timestamp.h" #include "threadutils.h" +#include "optional.h" class Timer { - boost::function callback; + std::function callback; Mutex mutex; ConditionVariable cond; // Stores the handle to a bgthread, which is created upon demand. (Previously // the thread was created in the constructor, but addressed sanitized (ASAN) // builds of R would hang when pthread_create was called during dlopen.) - boost::optional bgthread; - boost::optional wakeAt; + Optional bgthread; + Optional wakeAt; bool stopped; static int bg_main_func(void*); void bg_main(); public: - Timer(const boost::function& callback); + Timer(const std::function& callback); virtual ~Timer(); // Schedules the timer to fire next at the specified time. diff -Nru r-cran-later-1.1.0.1+dfsg/src/timestamp.h r-cran-later-1.3.0+dfsg/src/timestamp.h --- r-cran-later-1.1.0.1+dfsg/src/timestamp.h 2019-09-27 17:34:26.000000000 +0000 +++ r-cran-later-1.3.0+dfsg/src/timestamp.h 2021-08-17 20:05:55.000000000 +0000 @@ -1,7 +1,7 @@ #ifndef _TIMESTAMP_H_ #define _TIMESTAMP_H_ -#include +#include // Impl abstract class; implemented by platform-specific classes class TimestampImpl { @@ -15,8 +15,8 @@ class Timestamp { private: - boost::shared_ptr p_impl; - + std::shared_ptr p_impl; + public: Timestamp(); Timestamp(double secs); @@ -25,7 +25,7 @@ bool future() const { return p_impl->future(); } - + // Comparison operators bool operator<(const Timestamp& other) const { return p_impl->less(other.p_impl.get()); @@ -33,7 +33,7 @@ bool operator>(const Timestamp& other) const { return p_impl->greater(other.p_impl.get()); } - + // Diff double diff_secs(const Timestamp& other) const { return p_impl->diff_secs(other.p_impl.get()); diff -Nru r-cran-later-1.1.0.1+dfsg/src/timestamp_unix.cpp r-cran-later-1.3.0+dfsg/src/timestamp_unix.cpp --- r-cran-later-1.1.0.1+dfsg/src/timestamp_unix.cpp 2019-09-27 17:34:26.000000000 +0000 +++ r-cran-later-1.3.0+dfsg/src/timestamp_unix.cpp 2021-08-17 20:05:55.000000000 +0000 @@ -5,9 +5,9 @@ #include "timeconv.h" void get_current_time(timespec *ts) { - timeval tv; - gettimeofday(&tv, NULL); - *ts = timevalToTimespec(tv); + // CLOCK_MONOTONIC ensures that we never get timestamps that go backward in + // time due to clock adjustment. https://github.com/r-lib/later/issues/150 + clock_gettime(CLOCK_MONOTONIC, ts); } class TimestampImplPosix : public TimestampImpl { diff -Nru r-cran-later-1.1.0.1+dfsg/tests/testthat/test-run_now.R r-cran-later-1.3.0+dfsg/tests/testthat/test-run_now.R --- r-cran-later-1.1.0.1+dfsg/tests/testthat/test-run_now.R 2019-09-27 17:34:26.000000000 +0000 +++ r-cran-later-1.3.0+dfsg/tests/testthat/test-run_now.R 2021-08-17 20:05:55.000000000 +0000 @@ -59,6 +59,9 @@ }) test_that("run_now wakes up when a background thread calls later()", { + # Skip due to false positives on UBSAN + skip_if(using_ubsan()) + env <- new.env() Rcpp::sourceCpp(system.file("bgtest.cpp", package = "later"), env = env) # The background task sleeps @@ -67,11 +70,15 @@ x <- system.time({ result <- later::run_now(3) }) - expect_lt(as.numeric(x[["elapsed"]]), 1.25) + # Wait for up to 1.5 seconds (for slow systems) + expect_lt(as.numeric(x[["elapsed"]]), 1.5) expect_true(result) }) test_that("When callbacks have tied timestamps, they respect order of creation", { + # Skip due to false positives on UBSAN + skip_if(using_ubsan()) + expect_error(testCallbackOrdering(), NA) Rcpp::sourceCpp(code = '