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
|