-/////////////////////////////////////////////////////////////////////////////
-// License (GPLv2+):
-// This program is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation; either version 2 of the License, or (at
-// your option) any later version.
-//
-// This program is distributed in the hope that it will be useful, but
-// WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-/////////////////////////////////////////////////////////////////////////////
+// SPDX-License-Identifier: GPL-2.0-or-later
/**
* @file DiffThread.cpp
*
* @brief Code for DiffThread class
*/
-// RCS ID line follows -- this is updated by CVS
-// $Id$
-#include "stdafx.h"
-#include "diffcontext.h"
-#include "diffthread.h"
-#include "diff.h"
-#include "DirScan.h"
+#include "pch.h"
+#include "DiffThread.h"
+#include <cassert>
+#include <climits>
+#include <Poco/Thread.h>
+#include <Poco/Semaphore.h>
+#include "UnicodeString.h"
+#include "CompareStats.h"
+#include "IAbortable.h"
+#include "Plugins.h"
+#include "DebugNew.h"
-/**
- * @brief Static structure for sharing data with thread
- */
-static DiffFuncStruct diffParam;
+using Poco::Thread;
+using Poco::Semaphore;
-/**
- * @brief Default constructor
- */
-CDiffThread::CDiffThread()
-{
- m_pDiffContext = NULL;
- m_thread = NULL;
- diffParam.nThreadState = THREAD_NOTSTARTED;
-}
+// Thread functions
+static void DiffThreadCollect(void *lpParam);
+static void DiffThreadCompare(void *lpParam);
-CDiffThread::~CDiffThread()
+/** @brief abort handler for CDiffThread -- just a gateway to CDiffThread */
+class DiffThreadAbortable : public IAbortable
{
+// Implement DirScan's IAbortable
+public:
+ virtual bool ShouldAbort() const override { return m_diffthread->ShouldAbort(); }
-}
+// All this object does is forward ShouldAbort calls to its containing CDiffThread
+
+ explicit DiffThreadAbortable(CDiffThread * diffthread) : m_diffthread(diffthread) { }
+ CDiffThread * m_diffthread;
+};
/**
- * @brief Sets context pointer forwarded to thread
+ * @brief Default constructor.
*/
-CDiffContext * CDiffThread::SetContext(CDiffContext * pCtx)
+CDiffThread::CDiffThread()
+: m_pDiffContext(nullptr)
+, m_bAborting(false)
+, m_bPaused(false)
+, m_pDiffParm(new DiffFuncStruct)
+, m_pAbortgate(new DiffThreadAbortable(this))
{
- CDiffContext *pTempContext = m_pDiffContext;
- m_pDiffContext = pCtx;
- return pTempContext;
}
/**
- * @brief Start directory compare thread
+ * @brief Destructor, release resources.
*/
-UINT CDiffThread::CompareDirectories(CString dir1, CString dir2)
+CDiffThread::~CDiffThread()
{
- diffParam.path1 = dir1;
- diffParam.path2 = dir2;
- diffParam.context = m_pDiffContext;
- diffParam.msgUIUpdate = m_msgUpdateUI;
- diffParam.hWindow = m_hWnd;
-
- diffParam.nThreadState = THREAD_COMPARING;
- m_thread = AfxBeginThread(DiffThread, (LPVOID)&diffParam);
- return 1;
+ delete m_pDiffParm->pSemaphore;
}
/**
- * @brief Set window receiving messages thread sends
+ * @brief runtime interface for child thread, called on child thread
*/
-void CDiffThread::SetHwnd(HWND hWnd)
+bool CDiffThread::ShouldAbort() const
{
- m_hWnd = hWnd;
+ while (m_bPaused && !m_bAborting)
+ Poco::Thread::sleep(100);
+ return m_bAborting;
}
/**
- * @brief Set message-id and -number for messages thread sends to window
+ * @brief Start and run directory compare thread.
+ * @return Success (1) or error for thread. Currently always 1.
*/
-void CDiffThread::SetMessageIDs(UINT updateMsg, UINT statusMsg)
+unsigned CDiffThread::CompareDirectories()
{
- m_msgUpdateUI = updateMsg;
- m_msgUpdateStatus = statusMsg;
+ assert(m_pDiffParm->nThreadState != THREAD_COMPARING);
+
+ m_pDiffParm->context = m_pDiffContext;
+ m_pDiffParm->m_pAbortgate = m_pAbortgate.get();
+ m_bAborting = false;
+ m_bPaused = false;
+
+ m_pDiffParm->nThreadState = THREAD_COMPARING;
+
+ delete m_pDiffParm->pSemaphore;
+ m_pDiffParm->pSemaphore = new Semaphore(0, LONG_MAX);
+
+ m_pDiffParm->context->m_pCompareStats->SetCompareState(CompareStats::STATE_START);
+
+ m_threads[0].start(DiffThreadCollect, m_pDiffParm.get());
+ m_threads[1].start(DiffThreadCompare, m_pDiffParm.get());
+
+ return 1;
}
/**
- * @brief Returns thread's current state
+ * @brief Item collection thread function.
+ *
+ * This thread is responsible for finding and collecting all items to compare
+ * to the item list.
+ * @param [in] lpParam Pointer to parameter structure.
+ * @return Thread's return value.
*/
-UINT CDiffThread::GetThreadState()
+static void DiffThreadCollect(void *pParam)
{
- return diffParam.nThreadState;
-}
+ DiffFuncStruct *myStruct = static_cast<DiffFuncStruct *>(pParam);
+
+ // Stash abortable interface into context
+ myStruct->context->SetAbortable(myStruct->m_pAbortgate);
+
+ if (myStruct->m_fncCollect)
+ myStruct->m_fncCollect(myStruct);
+
+ // Release Semaphore() once again to signal that collect phase is ready
+ myStruct->pSemaphore->set();
+
+ // Send message to UI to update
+ int event = CDiffThread::EVENT_COLLECT_COMPLETED;
+ myStruct->m_listeners.notify(myStruct, event);
+};
/**
- * @brief Directory compare thread function
- * Calls diffutils's compare_files() and after compare is ready
+ * @brief Folder compare thread function.
+ *
+ * Compares items in item list. After compare is ready
* sends message to UI so UI can update itself.
+ * @param [in] lpParam Pointer to parameter structure.
+ * @return Thread's return value.
*/
-UINT DiffThread(LPVOID lpParam)
+static void DiffThreadCompare(void *pParam)
{
- DiffFuncStruct *myStruct = (DiffFuncStruct *) lpParam;
- HWND hWnd = myStruct->hWindow;
- UINT msgID = myStruct->msgUIUpdate;
-
- bool casesensitive = false;
- int depth = -1;
- CString subdir; // blank to start at roots specified in diff context
- DirScan(subdir, myStruct->context, casesensitive, depth);
-
+ DiffFuncStruct *myStruct = static_cast<DiffFuncStruct *>(pParam);
+ CAssureScriptsForThread scriptsForRescan;
+
+ // Stash abortable interface into context
+ myStruct->context->SetAbortable(myStruct->m_pAbortgate);
+
+ myStruct->context->m_pCompareStats->SetCompareState(CompareStats::STATE_COMPARE);
+
+ // Now do all pending file comparisons
+ myStruct->m_fncCompare(myStruct);
+
+ myStruct->context->m_pCompareStats->SetCompareState(CompareStats::STATE_IDLE);
+
// Send message to UI to update
- diffParam.nThreadState = THREAD_COMPLETED;
- SendMessage(hWnd, msgID, NULL, NULL);
- return 1;
+ myStruct->nThreadState = CDiffThread::THREAD_COMPLETED;
+ int event = CDiffThread::EVENT_COMPARE_COMPLETED;
+ myStruct->m_listeners.notify(myStruct, event);
}