LCOV - code coverage report
Current view: top level - autotest/cpp - bug1488.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 41 47 87.2 %
Date: 2025-01-18 12:42:00 Functions: 8 8 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL Core
       4             :  * Purpose:  Test fix for https://github.com/OSGeo/gdal/issues/1488 (concurrency
       5             :  *issue with overviews) Author:   Even Rouault, <even dot rouault at spatialys
       6             :  *dot com>
       7             :  *
       8             :  ******************************************************************************
       9             :  * Copyright (c) 2019, Even Rouault <even dot rouault at spatialys dot com>
      10             :  * Copyright (c) 2019, Thomas Bonfort <thomas.bonfort at gmail.com>
      11             :  *
      12             :  * SPDX-License-Identifier: MIT
      13             :  ****************************************************************************/
      14             : 
      15             : #include "gdal.h"
      16             : #include "cpl_multiproc.h"
      17             : 
      18             : #include "test_data.h"
      19             : 
      20             : #include "gtest_include.h"
      21             : 
      22             : namespace
      23             : {
      24             : 
      25             : // ---------------------------------------------------------------------------
      26             : 
      27             : static GDALDriverH hTIFFDrv = nullptr;
      28             : static volatile int bThread1Finished = FALSE;
      29             : static volatile int bThread2Finished = FALSE;
      30             : static volatile int bContinue = TRUE;
      31             : 
      32             : const char *szSrcDataset = TUT_ROOT_DATA_DIR "/bug1488.tif";
      33             : 
      34             : static int CPL_STDCALL myProgress(double, const char *, void *);
      35             : 
      36          17 : static int CPL_STDCALL myProgress(double, const char *, void *)
      37             : {
      38          17 :     return bContinue;
      39             : }
      40             : 
      41             : static void CPL_STDCALL myErrorHandler(CPLErr, CPLErrorNum, const char *msg);
      42             : 
      43           2 : static void CPL_STDCALL myErrorHandler(CPLErr, CPLErrorNum errorNum,
      44             :                                        const char *msg)
      45             : {
      46           2 :     if (errorNum != CPLE_UserInterrupt &&
      47           0 :         strstr(msg, "User terminated") == nullptr)
      48             :     {
      49           0 :         fprintf(stderr, "An error occurred: %s\n", msg);
      50           0 :         fprintf(stderr, "Likely a threading issue !\n");
      51           0 :         ASSERT_TRUE(false);
      52             :     }
      53             : }
      54             : 
      55           1 : static void worker_thread1(void *)
      56             : {
      57             : 
      58           1 :     GDALDatasetH hDataset = GDALOpen("/vsimem/thread1.tif", GA_Update);
      59           1 :     ASSERT_TRUE(hDataset != nullptr);
      60             : 
      61           1 :     int levels[1] = {2};
      62           1 :     int bands[3] = {1, 2, 3};
      63           1 :     CPLErr eErr = GDALBuildOverviews(hDataset, "AVERAGE", 1, levels, 3, bands,
      64             :                                      myProgress, nullptr);
      65             :     (void)eErr;
      66           1 :     GDALClose(hDataset);
      67           1 :     VSIUnlink("/vsimem/thread1.tif");
      68           1 :     bThread1Finished = TRUE;
      69             : }
      70             : 
      71           1 : static void worker_thread2(void *)
      72             : {
      73             : 
      74           1 :     GDALDatasetH hSrc = GDALOpen(szSrcDataset, GA_ReadOnly);
      75           1 :     ASSERT_TRUE(hSrc != nullptr);
      76           1 :     const char *const tops[] = {"TILED=YES", "COMPRESS=WEBP", nullptr};
      77             :     GDALDatasetH hDataset =
      78           1 :         GDALCreateCopy(GDALGetDriverByName("GTiff"), "/vsimem/thread2.tif",
      79             :                        hSrc, TRUE, tops, myProgress, nullptr);
      80           1 :     GDALClose(hDataset);
      81           1 :     GDALClose(hSrc);
      82           1 :     VSIUnlink("/vsimem/thread2.tif");
      83           1 :     bThread2Finished = TRUE;
      84             : }
      85             : 
      86           4 : TEST(bug1488, test)
      87             : {
      88           1 :     GDALAllRegister();
      89             : 
      90           1 :     hTIFFDrv = GDALGetDriverByName("GTiff");
      91           1 :     if (!hTIFFDrv)
      92             :     {
      93           0 :         GTEST_SKIP() << "GTIFF driver missing";
      94             :         return;
      95             :     }
      96             :     const char *pszCO =
      97           1 :         GDALGetMetadataItem(hTIFFDrv, GDAL_DMD_CREATIONOPTIONLIST, nullptr);
      98           1 :     if (pszCO == nullptr || strstr(pszCO, "WEBP") == nullptr)
      99             :     {
     100           0 :         GTEST_SKIP() << "WEBP driver missing";
     101             :         return;
     102             :     }
     103             : 
     104           1 :     GDALSetCacheMax(30 * 1000 * 1000);
     105             : 
     106           1 :     CPLSetErrorHandler(myErrorHandler);
     107             : 
     108           1 :     VSISync(szSrcDataset, "/vsimem/thread1.tif", nullptr, nullptr, nullptr,
     109             :             nullptr);
     110             : 
     111           1 :     CPLJoinableThread *t1 = CPLCreateJoinableThread(worker_thread1, nullptr);
     112           1 :     CPLJoinableThread *t2 = CPLCreateJoinableThread(worker_thread2, nullptr);
     113           1 :     int nCountSeconds = 0;
     114           4 :     while (!bThread1Finished && !bThread2Finished)
     115             :     {
     116           3 :         CPLSleep(1);
     117           3 :         nCountSeconds++;
     118           3 :         if (nCountSeconds == 2)
     119             :         {
     120             :             /* After 2 seconds without errors, assume no threading issue, and */
     121             :             /* early exit */
     122           1 :             bContinue = FALSE;
     123             :         }
     124             :     }
     125           1 :     CPLJoinThread(t1);
     126           1 :     CPLJoinThread(t2);
     127             : }
     128             : 
     129             : }  // namespace

Generated by: LCOV version 1.14