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: 2024-11-21 22:18:42 Functions: 8 8 100.0 %

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

Generated by: LCOV version 1.14