Skip to content

Commit 03b1040

Browse files
committed
Scintilla callback - first steps to fixes
- shared_ptr should not be passed by reference when we don't know how long it will live for - callback functions now stored as managed boost::python::object's to ensure we keep the ref count correct - Simple test now passes, and doesn't crash. - "Per hand" testing occassionally results in crash, can't reproduce in test yet
1 parent 597f8f8 commit 03b1040

12 files changed

Lines changed: 172 additions & 80 deletions

PythonScript/project/PythonScript2010.vcxproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,7 @@ xcopy $(ProjectDir)..\python_tests\*.* "e:\notepadtest\unicode\plugins\config\py
256256
<ClInclude Include="..\python_tests\tests\ConsoleTestCase.py">
257257
<FileType>Document</FileType>
258258
</ClInclude>
259+
<None Include="..\python_tests\tests\ScintillaCallbackTestCase.py" />
259260
<None Include="..\python_tests\tests\__init__.py" />
260261
<None Include="..\python_tests\__init__.py" />
261262
<None Include="..\res\FolderClosed.ico" />
@@ -315,6 +316,7 @@ xcopy $(ProjectDir)..\python_tests\*.* "e:\notepadtest\unicode\plugins\config\py
315316
<ClInclude Include="..\src\ConsoleDialog.h" />
316317
<ClInclude Include="..\src\ConsoleInterface.h" />
317318
<ClInclude Include="..\src\ConstString.h" />
319+
<ClInclude Include="..\src\DebugTrace.h" />
318320
<ClInclude Include="..\src\DynamicIDManager.h" />
319321
<ClInclude Include="..\src\Enums.h" />
320322
<ClInclude Include="..\src\GroupNotFoundException.h" />
@@ -323,6 +325,7 @@ xcopy $(ProjectDir)..\python_tests\*.* "e:\notepadtest\unicode\plugins\config\py
323325
<ClInclude Include="..\src\Match.h" />
324326
<ClInclude Include="..\src\MatchPython.h" />
325327
<ClInclude Include="..\src\MenuManager.h" />
328+
<ClInclude Include="..\src\MutexHolder.h" />
326329
<ClInclude Include="..\src\NotepadPlusBuffer.h" />
327330
<ClInclude Include="..\src\NotepadPlusWrapper.h" />
328331
<ClInclude Include="..\src\NotepadPython.h" />

PythonScript/project/PythonScript2010.vcxproj.filters

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
<None Include="..\python_tests\__init__.py">
4747
<Filter>PythonTests</Filter>
4848
</None>
49+
<None Include="..\python_tests\tests\ScintillaCallbackTestCase.py" />
4950
</ItemGroup>
5051
<ItemGroup>
5152
<ClCompile Include="..\src\PythonHandler.cpp">
@@ -323,6 +324,12 @@
323324
<ClInclude Include="..\python_tests\tests\ConsoleTestCase.py">
324325
<Filter>PythonTests\Tests</Filter>
325326
</ClInclude>
327+
<ClInclude Include="..\src\DebugTrace.h">
328+
<Filter>Header Files</Filter>
329+
</ClInclude>
330+
<ClInclude Include="..\src\MutexHolder.h">
331+
<Filter>Header Files</Filter>
332+
</ClInclude>
326333
</ItemGroup>
327334
<ItemGroup>
328335
<ResourceCompile Include="..\res\PythonScript.rc">

PythonScript/python_tests/tests/ScintillaCallbackTestCase.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,26 +4,37 @@
44

55
class ScintillaCallbackTestCase(unittest.TestCase):
66
def setUp(self):
7-
pass
7+
notepad.new()
88

99
def tearDown(self):
10+
notepad.clearCallbacks()
1011
editor.clearCallbacks()
12+
editor.setSavePoint()
13+
notepad.close()
1114

1215
def updateui_callback(self, args):
1316
self.assertNotEqual(args['updated'], 0)
1417
self.assertNotEqual(args['updated'], None)
1518
self.called = True
1619

20+
1721
def test_callback_updateui(self):
1822
self.called = False
19-
editor.callback(lambda args: self.updateui_callback(args), [SCINTILLANOTIFICATION.UPDATEUI])
23+
editor.callback(lambda args: self.updateui_callback(args), [SCINTILLANOTIFICATION.UPDATEUI], )
2024
notepad.new()
2125
editor.write('test')
2226
time.sleep(0.2) # wait for the event to have run
2327
editor.clearCallbacks()
2428
self.assertEqual(self.called, True)
2529

2630

31+
def modified_callback(self, args):
32+
console.write('modified\n')
33+
34+
def test_modified_callback(self):
35+
editor.callback(lambda a: self.modified_callback(a), [SCINTILLANOTIFICATION.MODIFIED])
36+
for _ in range(250):
37+
editor.write('test\n')
2738

2839

2940
suite = unittest.TestLoader().loadTestsFromTestCase(ScintillaCallbackTestCase)

PythonScript/src/DebugTrace.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#ifndef DEBUGTRACE_20140215_H
2+
#define DEBUGTRACE_20140215_H
3+
4+
#define DEBUG_TRACE(msg) { std::wstringstream debug; debug << L"PY>" << ::GetCurrentThreadId() << L" " << msg; OutputDebugString(debug.str().c_str()); }
5+
6+
7+
#endif // DEBUGTRACE_20140215_H

PythonScript/src/MutexHolder.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
namespace NppPythonScript
2+
{
3+
class MutexHolder
4+
{
5+
public:
6+
MutexHolder(HANDLE mutex)
7+
: m_mutex(mutex)
8+
{
9+
DEBUG_TRACE(L"Waiting for mutex\n");
10+
DWORD result = ::WaitForSingleObjectEx(mutex, INFINITE, FALSE);
11+
DEBUG_TRACE(result);
12+
DEBUG_TRACE(L"Got mutex\n");
13+
}
14+
15+
virtual ~MutexHolder()
16+
{
17+
::ReleaseMutex(m_mutex);
18+
DEBUG_TRACE(L"Released mutex");
19+
}
20+
21+
private:
22+
HANDLE m_mutex;
23+
};
24+
}

PythonScript/src/PyProducerConsumer.h

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#ifndef _PYPRODUCER_H
22
#define _PYPRODUCER_H
3+
#include "DebugTrace.h"
34

45
namespace NppPythonScript
56
{
@@ -17,8 +18,8 @@ class PyProducerConsumer
1718
bool consumerBusy();
1819

1920
protected:
20-
bool produce(const std::shared_ptr<DataT>& data);
21-
virtual void consume(const std::shared_ptr<DataT>& data) = 0;
21+
bool produce(std::shared_ptr<DataT> data);
22+
virtual void consume(std::shared_ptr<DataT> data) = 0;
2223
virtual void queueComplete() { };
2324
DWORD getConsumerThreadID() { return m_dwThreadId; };
2425

@@ -76,7 +77,7 @@ void PyProducerConsumer<DataT>::stopConsumer()
7677
}
7778

7879
template <typename DataT>
79-
bool PyProducerConsumer<DataT>::produce(const std::shared_ptr<DataT>& data)
80+
bool PyProducerConsumer<DataT>::produce(std::shared_ptr<DataT> data)
8081
{
8182
bool retVal = false;
8283
DWORD mutexResult = WaitForSingleObject(m_queueMutex, INFINITE);
@@ -141,6 +142,7 @@ void PyProducerConsumer<DataT>::consumer()
141142

142143
if (queueAvailable == WAIT_OBJECT_0)
143144
{
145+
DEBUG_TRACE(L"Popping Queue\n");
144146
queueEmpty = false;
145147
std::shared_ptr<DataT> data = m_queue.front();
146148
m_queue.pop();
@@ -151,12 +153,22 @@ void PyProducerConsumer<DataT>::consumer()
151153
}
152154

153155
ReleaseMutex(m_queueMutex);
154-
155-
consume(data);
156-
156+
157+
try {
158+
DEBUG_TRACE(L"Consuming...\n");
159+
consume(data);
160+
DEBUG_TRACE(L"End Consume\n");
161+
}
162+
catch(...) {
163+
queueEmpty = queueEmpty;
164+
}
165+
166+
157167
if (queueEmpty)
158168
{
169+
DEBUG_TRACE(L"Waiting for dataAvailable\n");
159170
waitResult = WaitForSingleObject(m_dataAvailable, 0);
171+
DEBUG_TRACE(L"dataAvailable signalled\n");
160172
if (waitResult != WAIT_OBJECT_0)
161173
{
162174
m_consuming = false;

PythonScript/src/PythonConsole.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,7 @@ void PythonConsole::queueComplete()
260260
}
261261
}
262262

263-
void PythonConsole::consume(const std::shared_ptr<std::string>& statement)
263+
void PythonConsole::consume(std::shared_ptr<std::string> statement)
264264
{
265265
PyGILState_STATE gstate = PyGILState_Ensure();
266266
bool continuePrompt = false;

PythonScript/src/PythonConsole.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ class PythonConsole : public NppPythonScript::PyProducerConsumer<std::string>, p
7070
static boost::python::str getEncoding() { return boost::python::str("utf-8"); }
7171

7272
protected:
73-
virtual void consume(const std::shared_ptr<std::string>& statement);
73+
virtual void consume(std::shared_ptr<std::string> statement);
7474
virtual void queueComplete();
7575

7676
private:

PythonScript/src/PythonHandler.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ bool PythonHandler::runScript(const char *filename,
237237
return retVal;
238238
}
239239

240-
void PythonHandler::consume(const std::shared_ptr<RunScriptArgs>& args)
240+
void PythonHandler::consume(std::shared_ptr<RunScriptArgs> args)
241241
{
242242
runScriptWorker(args);
243243
}

PythonScript/src/PythonHandler.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ class PythonHandler : public NppPythonScript::PyProducerConsumer<RunScriptArgs>
6464

6565

6666
protected:
67-
void consume(const std::shared_ptr<RunScriptArgs>& args);
67+
void consume(std::shared_ptr<RunScriptArgs> args);
6868

6969
ScintillaWrapper* createScintillaWrapper();
7070
NotepadPlusWrapper* createNotepadPlusWrapper();

0 commit comments

Comments
 (0)