@@ -45,7 +45,11 @@ Countly &Countly::getInstance() {
4545}
4646
4747#ifdef COUNTLY_BUILD_TESTS
48- void Countly::halt () { _sharedInstance.reset (new Countly ()); }
48+ void Countly::halt () {
49+ if (_sharedInstance) {
50+ _sharedInstance->stop (); // joins threads, releases mutex normally
51+ }
52+ _sharedInstance.reset (new Countly ()); }
4953#endif
5054
5155/* *
@@ -157,6 +161,16 @@ void Countly::disableAutoEventsOnUserProperties() {
157161 mutex->unlock ();
158162}
159163
164+ void Countly::enableImmediateRequestOnStop () {
165+ if (is_sdk_initialized) {
166+ log (LogLevel::WARNING, " [Countly][enableImmediateRequestOnStop] You can not enable immediate request on stop after SDK initialization." );
167+ return ;
168+ }
169+
170+ std::lock_guard<std::mutex> lk (*mutex);
171+ configuration->immediateRequestOnStop = true ;
172+ }
173+
160174void Countly::setMetrics (const std::string &os, const std::string &os_version, const std::string &device, const std::string &resolution, const std::string &carrier, const std::string &app_version) {
161175 if (is_sdk_initialized) {
162176 log (LogLevel::WARNING, " [Countly] setMetrics, This method can't be called after SDK initialization. Returning." );
@@ -566,9 +580,11 @@ void Countly::stop() {
566580}
567581
568582void Countly::_deleteThread () {
569- mutex->lock ();
570- stop_thread = true ;
571- mutex->unlock ();
583+ {
584+ std::lock_guard<std::mutex> lk (*mutex);
585+ stop_thread = true ;
586+ }
587+ stop_cv.notify_one ();
572588 if (thread && thread->joinable ()) {
573589 try {
574590 thread->join ();
@@ -580,9 +596,13 @@ void Countly::_deleteThread() {
580596}
581597
582598void Countly::setUpdateInterval (size_t milliseconds) {
583- mutex->lock ();
584- wait_milliseconds = milliseconds;
585- mutex->unlock ();
599+ {
600+ std::lock_guard<std::mutex> lk (*mutex);
601+ wait_milliseconds = milliseconds;
602+ }
603+ if (configuration->immediateRequestOnStop ) {
604+ stop_cv.notify_one ();
605+ }
586606}
587607
588608void Countly::addEvent (const cly::Event &event) {
@@ -1380,30 +1400,69 @@ std::chrono::system_clock::duration Countly::getSessionDuration(std::chrono::sys
13801400std::chrono::system_clock::duration Countly::getSessionDuration () { return Countly::getSessionDuration (Countly::getTimestamp ()); }
13811401
13821402void Countly::updateLoop () {
1383- log (LogLevel::DEBUG, " [Countly] updateLoop, Start" );
1384- mutex->lock ();
1385- running = true ;
1386- mutex->unlock ();
1387- while (true ) {
1388- mutex->lock ();
1389- if (stop_thread) {
1390- stop_thread = false ;
1403+ log (LogLevel::DEBUG, " [Countly][updateLoop]" );
1404+ {
1405+ std::lock_guard<std::mutex> lk (*mutex);
1406+ running = true ;
1407+ }
1408+ try {
1409+ if (configuration->immediateRequestOnStop ) {
1410+ while (true ) {
1411+ {
1412+ std::unique_lock<std::mutex> lk (*mutex);
1413+ stop_cv.wait_for (lk, std::chrono::milliseconds (wait_milliseconds), [this ] {
1414+ return stop_thread.load ();
1415+ });
1416+ if (stop_thread) {
1417+ stop_thread = false ;
1418+ running = false ;
1419+ return ;
1420+ }
1421+ }
1422+ if (enable_automatic_session == true && configuration->manualSessionControl == false ) {
1423+ updateSession ();
1424+ } else if (configuration->manualSessionControl == true ) {
1425+ packEvents ();
1426+ }
1427+ requestModule->processQueue (mutex);
1428+ }
1429+ } else {
1430+ while (true ) {
1431+ size_t last_wait_milliseconds;
1432+ {
1433+ std::lock_guard<std::mutex> lk (*mutex);
1434+ if (stop_thread) {
1435+ stop_thread = false ;
1436+ break ;
1437+ }
1438+ last_wait_milliseconds = wait_milliseconds;
1439+ }
1440+ std::this_thread::sleep_for (std::chrono::milliseconds (last_wait_milliseconds));
1441+ if (enable_automatic_session == true && configuration->manualSessionControl == false ) {
1442+ updateSession ();
1443+ } else if (configuration->manualSessionControl == true ) {
1444+ packEvents ();
1445+ }
1446+ requestModule->processQueue (mutex);
1447+ }
1448+ std::lock_guard<std::mutex> lk (*mutex);
1449+ running = false ;
1450+ }
1451+ } catch (const std::exception &e) {
1452+ bool acquired = mutex->try_lock ();
1453+ running = false ;
1454+ log (LogLevel::ERROR, std::string (" [Countly][updateLoop] exception in update loop: " ) + e.what ());
1455+ if (acquired) {
13911456 mutex->unlock ();
1392- break ;
13931457 }
1394- size_t last_wait_milliseconds = wait_milliseconds;
1395- mutex->unlock ();
1396- std::this_thread::sleep_for (std::chrono::milliseconds (last_wait_milliseconds));
1397- if (enable_automatic_session == true && configuration->manualSessionControl == false ) {
1398- updateSession ();
1399- } else if (configuration->manualSessionControl == true ) {
1400- packEvents ();
1458+ } catch (...) {
1459+ bool acquired = mutex->try_lock ();
1460+ running = false ;
1461+ log (LogLevel::FATAL, " [Countly][updateLoop] unknown non-std::exception caught, stopping update loop" );
1462+ if (acquired) {
1463+ mutex->unlock ();
14011464 }
1402- requestModule->processQueue (mutex);
14031465 }
1404- mutex->lock ();
1405- running = false ;
1406- mutex->unlock ();
14071466}
14081467
14091468void Countly::enableRemoteConfig () {
0 commit comments