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
|