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-09-10 17:48:50 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             :     }
      95             :     else
      96             :     {
      97             :         const char *pszCO =
      98           1 :             GDALGetMetadataItem(hTIFFDrv, GDAL_DMD_CREATIONOPTIONLIST, nullptr);
      99           1 :         if (pszCO == nullptr || strstr(pszCO, "WEBP") == nullptr)
     100             :         {
     101           0 :             GTEST_SKIP() << "WEBP driver missing";
     102             :         }
     103             :         else
     104             :         {
     105           1 :             GDALSetCacheMax(30 * 1000 * 1000);
     106             : 
     107           1 :             CPLSetErrorHandler(myErrorHandler);
     108             : 
     109           1 :             VSISync(szSrcDataset, "/vsimem/thread1.tif", nullptr, nullptr,
     110             :                     nullptr, nullptr);
     111             : 
     112             :             CPLJoinableThread *t1 =
     113           1 :                 CPLCreateJoinableThread(worker_thread1, nullptr);
     114             :             CPLJoinableThread *t2 =
     115           1 :                 CPLCreateJoinableThread(worker_thread2, nullptr);
     116           1 :             int nCountSeconds = 0;
     117           4 :             while (!bThread1Finished && !bThread2Finished)
     118             :             {
     119           3 :                 CPLSleep(1);
     120           3 :                 nCountSeconds++;
     121           3 :                 if (nCountSeconds == 2)
     122             :                 {
     123             :                     /* After 2 seconds without errors, assume no threading issue, and */
     124             :                     /* early exit */
     125           1 :                     bContinue = FALSE;
     126             :                 }
     127             :             }
     128           1 :             CPLJoinThread(t1);
     129           1 :             CPLJoinThread(t2);
     130             :         }
     131             :     }
     132             : }
     133             : 
     134             : }  // namespace

Generated by: LCOV version 1.14