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 : * Permission is hereby granted, free of charge, to any person obtaining a
14 : * copy of this software and associated documentation files (the "Software"),
15 : * to deal in the Software without restriction, including without limitation
16 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
17 : * and/or sell copies of the Software, and to permit persons to whom the
18 : * Software is furnished to do so, subject to the following conditions:
19 : *
20 : * The above copyright notice and this permission notice shall be included
21 : * in all copies or substantial portions of the Software.
22 : *
23 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
24 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29 : * DEALINGS IN THE SOFTWARE.
30 : ****************************************************************************/
31 :
32 : #include "gdal.h"
33 : #include "cpl_multiproc.h"
34 :
35 : #include "test_data.h"
36 :
37 : #include "gtest_include.h"
38 :
39 : namespace
40 : {
41 :
42 : // ---------------------------------------------------------------------------
43 :
44 : static GDALDriverH hTIFFDrv = nullptr;
45 : static volatile int bThread1Finished = FALSE;
46 : static volatile int bThread2Finished = FALSE;
47 : static volatile int bContinue = TRUE;
48 :
49 : const char *szSrcDataset = TUT_ROOT_DATA_DIR "/bug1488.tif";
50 :
51 : static int CPL_STDCALL myProgress(double, const char *, void *);
52 :
53 17 : static int CPL_STDCALL myProgress(double, const char *, void *)
54 : {
55 17 : return bContinue;
56 : }
57 :
58 : static void CPL_STDCALL myErrorHandler(CPLErr, CPLErrorNum, const char *msg);
59 :
60 2 : static void CPL_STDCALL myErrorHandler(CPLErr, CPLErrorNum errorNum,
61 : const char *msg)
62 : {
63 2 : if (errorNum != CPLE_UserInterrupt &&
64 0 : strstr(msg, "User terminated") == nullptr)
65 : {
66 0 : fprintf(stderr, "An error occurred: %s\n", msg);
67 0 : fprintf(stderr, "Likely a threading issue !\n");
68 0 : ASSERT_TRUE(false);
69 : }
70 : }
71 :
72 1 : static void worker_thread1(void *)
73 : {
74 :
75 1 : GDALDatasetH hDataset = GDALOpen("/vsimem/thread1.tif", GA_Update);
76 1 : ASSERT_TRUE(hDataset != nullptr);
77 :
78 1 : int levels[1] = {2};
79 1 : int bands[3] = {1, 2, 3};
80 1 : CPLErr eErr = GDALBuildOverviews(hDataset, "AVERAGE", 1, levels, 3, bands,
81 : myProgress, nullptr);
82 : (void)eErr;
83 1 : GDALClose(hDataset);
84 1 : VSIUnlink("/vsimem/thread1.tif");
85 1 : bThread1Finished = TRUE;
86 : }
87 :
88 1 : static void worker_thread2(void *)
89 : {
90 :
91 1 : GDALDatasetH hSrc = GDALOpen(szSrcDataset, GA_ReadOnly);
92 1 : ASSERT_TRUE(hSrc != nullptr);
93 1 : const char *const tops[] = {"TILED=YES", "COMPRESS=WEBP", nullptr};
94 : GDALDatasetH hDataset =
95 1 : GDALCreateCopy(GDALGetDriverByName("GTiff"), "/vsimem/thread2.tif",
96 : hSrc, TRUE, tops, myProgress, nullptr);
97 1 : GDALClose(hDataset);
98 1 : GDALClose(hSrc);
99 1 : VSIUnlink("/vsimem/thread2.tif");
100 1 : bThread2Finished = TRUE;
101 : }
102 :
103 4 : TEST(bug1488, test)
104 : {
105 1 : GDALAllRegister();
106 :
107 1 : hTIFFDrv = GDALGetDriverByName("GTiff");
108 1 : if (!hTIFFDrv)
109 : {
110 0 : GTEST_SKIP() << "GTIFF driver missing";
111 : return;
112 : }
113 : const char *pszCO =
114 1 : GDALGetMetadataItem(hTIFFDrv, GDAL_DMD_CREATIONOPTIONLIST, nullptr);
115 1 : if (pszCO == nullptr || strstr(pszCO, "WEBP") == nullptr)
116 : {
117 0 : GTEST_SKIP() << "WEBP driver missing";
118 : return;
119 : }
120 :
121 1 : GDALSetCacheMax(30 * 1000 * 1000);
122 :
123 1 : CPLSetErrorHandler(myErrorHandler);
124 :
125 1 : VSISync(szSrcDataset, "/vsimem/thread1.tif", nullptr, nullptr, nullptr,
126 : nullptr);
127 :
128 1 : CPLJoinableThread *t1 = CPLCreateJoinableThread(worker_thread1, nullptr);
129 1 : CPLJoinableThread *t2 = CPLCreateJoinableThread(worker_thread2, nullptr);
130 1 : int nCountSeconds = 0;
131 4 : while (!bThread1Finished && !bThread2Finished)
132 : {
133 3 : CPLSleep(1);
134 3 : nCountSeconds++;
135 3 : if (nCountSeconds == 2)
136 : {
137 : /* After 2 seconds without errors, assume no threading issue, and */
138 : /* early exit */
139 1 : bContinue = FALSE;
140 : }
141 : }
142 1 : CPLJoinThread(t1);
143 1 : CPLJoinThread(t2);
144 : }
145 :
146 : } // namespace
|