1 /////////////////////////////////////////////////////////////////////////////
3 // This program is free software; you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation; either version 2 of the License, or (at
6 // your option) any later version.
8 // This program is distributed in the hope that it will be useful, but
9 // WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 // GNU General Public License for more details.
13 // You should have received a copy of the GNU General Public License
14 // along with this program; if not, write to the Free Software
15 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
16 /////////////////////////////////////////////////////////////////////////////
18 * @file DiffThread.cpp
20 * @brief Code for DiffThread class
22 // ID line follows -- this is updated by SVN
23 // $Id: DiffThread.cpp 6910 2009-07-12 09:06:54Z kimmov $
26 #include "UnicodeString.h"
27 #include "diffcontext.h"
28 #include "diffthread.h"
31 #include "DiffItemList.h"
32 #include "PathContext.h"
33 #include "CompareStats.h"
34 #include "IAbortable.h"
37 * @brief Force compare to be single-threaded.
38 * Set this to true in order to single step through entire compare process all
39 * in a single thread. Either edit this line, or breakpoint & change it in
40 * CompareDirectories() below.
42 * If you are going to debug compare procedure, you most probably need to set
43 * this to true. As Visual Studio seems to have real problems with debugging
44 * these threads otherwise.
46 static bool bSinglethreaded = false;
48 /** @brief abort handler for CDiffThread -- just a gateway to CDiffThread */
49 class DiffThreadAbortable : public IAbortable
51 // Implement DirScan's IAbortable
53 virtual bool ShouldAbort() const { return m_diffthread->ShouldAbort(); }
55 // All this object does is forward ShouldAbort calls to its containing CDiffThread
57 DiffThreadAbortable(CDiffThread * diffthread) : m_diffthread(diffthread) { }
58 CDiffThread * m_diffthread;
62 * @brief Default constructor.
64 CDiffThread::CDiffThread()
65 : m_pDiffContext(NULL)
70 ZeroMemory(&m_threads[0], sizeof(m_threads));
71 m_pDiffParm = new DiffFuncStruct;
72 m_pAbortgate = new DiffThreadAbortable(this);
76 * @brief Destructor, release resources.
78 CDiffThread::~CDiffThread()
80 CloseHandle(m_pDiffParm->hSemaphore);
86 * @brief Sets context pointer forwarded to thread.
87 * @param [in] pCtx Pointer to compare context.
89 void CDiffThread::SetContext(CDiffContext * pCtx)
91 m_pDiffContext = pCtx;
95 * @brief runtime interface for child thread, called on child thread
97 bool CDiffThread::ShouldAbort() const
102 while (::PeekMessage(&msg, 0, 0, 0, PM_NOREMOVE))
104 AfxGetApp()->PumpMessage();
111 * @brief Start and run directory compare thread.
112 * @param [in] dir1 First directory to compare.
113 * @param [in] dir2 Second directory to compare.
114 * @return Success (1) or error for thread. Currently always 1.
116 UINT CDiffThread::CompareDirectories(const String & dir1,
119 ASSERT(m_pDiffParm->nThreadState != THREAD_COMPARING);
121 m_pDiffParm->context = m_pDiffContext;
122 m_pDiffParm->msgUIUpdate = m_msgUpdateUI;
123 m_pDiffParm->hWindow = m_hWnd;
124 m_pDiffParm->m_pAbortgate = m_pAbortgate;
125 m_pDiffParm->bOnlyRequested = m_bOnlyRequested;
128 m_pDiffParm->nThreadState = THREAD_COMPARING;
130 m_pDiffParm->hSemaphore = CreateSemaphore(0, 0, LONG_MAX, 0);
132 m_pDiffParm->context->m_pCompareStats->SetCompareState(CompareStats::STATE_START);
136 if (m_bOnlyRequested == FALSE)
137 DiffThreadCollect(m_pDiffParm);
138 DiffThreadCompare(m_pDiffParm);
142 if (m_bOnlyRequested == FALSE)
143 m_threads[0] = AfxBeginThread(DiffThreadCollect, m_pDiffParm);
144 m_threads[1] = AfxBeginThread(DiffThreadCompare, m_pDiffParm);
151 * @brief Set window receiving messages thread sends.
152 * @param [in] hWnd Hand to window to receive messages.
154 void CDiffThread::SetHwnd(HWND hWnd)
160 * @brief Set message-id for update message.
161 * @param [in] updateMsg Message-id for update message.
163 void CDiffThread::SetMessageIDs(UINT updateMsg)
165 m_msgUpdateUI = updateMsg;
169 * @brief Selects to compare all or only selected items.
170 * @param [in] bSelected If TRUE only selected items are compared.
172 void CDiffThread::SetCompareSelected(bool bSelected /*=FALSE*/)
174 m_bOnlyRequested = bSelected;
178 * @brief Returns thread's current state
180 UINT CDiffThread::GetThreadState() const
182 return m_pDiffParm->nThreadState;
186 * @brief Item collection thread function.
188 * This thread is responsible for finding and collecting all items to compare
190 * @param [in] lpParam Pointer to parameter structure.
191 * @return Thread's return value.
193 UINT DiffThreadCollect(LPVOID lpParam)
196 DiffFuncStruct *myStruct = (DiffFuncStruct *) lpParam;
198 ASSERT(myStruct->bOnlyRequested == FALSE);
200 // Stash abortable interface into context
201 myStruct->context->SetAbortable(myStruct->m_pAbortgate);
203 // keep the scripts alive during the Rescan
204 // when we exit the thread, we delete this and release the scripts
205 CAssureScriptsForThread scriptsForRescan;
207 bool casesensitive = false;
208 int depth = myStruct->context->m_bRecursive ? -1 : 0;
210 paths = myStruct->context->GetNormalizedPaths();
212 LPCTSTR subdir[3] = {_T(""), _T(""), _T("")}; // blank to start at roots specified in diff context
214 _CrtMemState memStateBefore;
215 _CrtMemState memStateAfter;
216 _CrtMemState memStateDiff;
217 _CrtMemCheckpoint(&memStateBefore);
220 // Build results list (except delaying file comparisons until below)
221 DirScan_GetItems(paths, subdir, myStruct,
222 casesensitive, depth, NULL, myStruct->context->m_bWalkUniques);
225 _CrtMemCheckpoint(&memStateAfter);
226 _CrtMemDifference(&memStateDiff, &memStateBefore, &memStateAfter);
227 _CrtMemDumpStatistics(&memStateDiff);
230 // ReleaseSemaphore() once again to signal that collect phase is ready
231 ReleaseSemaphore(myStruct->hSemaphore, 1, 0);
233 // Send message to UI to update
234 PostMessage(myStruct->hWindow, myStruct->msgUIUpdate, 2, myStruct->bOnlyRequested);
239 * @brief Folder compare thread function.
241 * Compares items in item list. After compare is ready
242 * sends message to UI so UI can update itself.
243 * @param [in] lpParam Pointer to parameter structure.
244 * @return Thread's return value.
246 UINT DiffThreadCompare(LPVOID lpParam)
248 DiffFuncStruct *myStruct = (DiffFuncStruct *) lpParam;
250 // Stash abortable interface into context
251 myStruct->context->SetAbortable(myStruct->m_pAbortgate);
253 // keep the scripts alive during the Rescan
254 // when we exit the thread, we delete this and release the scripts
255 CAssureScriptsForThread scriptsForRescan;
257 myStruct->context->m_pCompareStats->SetCompareState(CompareStats::STATE_COMPARE);
259 // Now do all pending file comparisons
260 if (myStruct->bOnlyRequested)
261 DirScan_CompareRequestedItems(myStruct, NULL);
263 DirScan_CompareItems(myStruct, NULL);
265 myStruct->context->m_pCompareStats->SetCompareState(CompareStats::STATE_IDLE);
267 // Send message to UI to update
268 myStruct->nThreadState = CDiffThread::THREAD_COMPLETED;
269 // msgID=MSG_UI_UPDATE=1025 (2005-11-29, Perry)
270 PostMessage(myStruct->hWindow, myStruct->msgUIUpdate, NULL, myStruct->bOnlyRequested);