1 /*
2  * Part of WCM Commander
3  * https://github.com/corporateshark/WCMCommander
4  * wcm@linderdaum.com
5  */
6 
7 #include "operwin.h"
8 
9 static Mutex operMutex; //блокировать при изменении operStopList, и при к threadId и tNode  в OperThreadWin !!!
10 
11 static OperThreadNode* volatile operStopList = 0;
12 
13 
CallBack(OperCallback f,void * data)14 int OperThreadNode::CallBack( OperCallback f, void* data )
15 {
16 	MutexLock lock( &mutex );
17 	cbRet = -1;
18 	cbData = data;
19 	cbFunc = f;
20 
21 	if ( !WinThreadSignal( 1 ) )
22 	{
23 		return -1;
24 	}
25 
26 	cbCond.Wait( &mutex );
27 	return cbRet;
28 }
29 
~OperThreadNode()30 OperThreadNode::~OperThreadNode()
31 {
32 	if ( !stopped ) { fprintf( stderr, "!!! BUG ~OperThreadNode 1\n" ); }
33 }
34 
35 
36 
DBGPrintStoppingList()37 void OperThreadWin::DBGPrintStoppingList()
38 {
39 	MutexLock lock1( &operMutex );
40 
41 	OperThreadNode* p;
42 
43 	for ( p = operStopList; p; p = p->next )
44 	{
45 		MutexLock lock2( &p->mutex );
46 		printf( "stopped thread %s\n", p->threadInfo.data() ? p->threadInfo.data() : "<empty info>" );
47 	}
48 }
49 
SetStopFlag()50 void OperThreadWin::SetStopFlag()
51 {
52 	if ( tNode )
53 	{
54 		MutexLock lockNode( &tNode->mutex );
55 		tNode->stopped = true;
56 	}
57 }
58 
StopThread()59 void OperThreadWin::StopThread()
60 {
61 	MutexLock lock( &operMutex );
62 
63 	if ( !tNode )
64 	{
65 		threadId = -1;
66 		return;
67 	}
68 
69 	MutexLock lockNode( &tNode->mutex );
70 	tNode->stopped = true;
71 	tNode->data = 0;
72 
73 	if ( !this->cbExecuted ) //!!!
74 	{
75 		tNode->cbRet = -1;
76 		tNode->cbCond.Signal(); // на всякий случай, вдруг сигнал о каллбаке послан, но сообщение еще до окна не дошло
77 	}
78 
79 	tNode->win = 0;
80 	tNode->prev = 0;
81 
82 	if ( operStopList ) { operStopList->prev = tNode; }
83 
84 	tNode->next = operStopList;
85 	operStopList = tNode;
86 	tNode = 0;
87 	threadId = -1;
88 }
89 
90 struct OperThreadParam: public iIntrusiveCounter
91 {
92 	OperThreadFunc func;
93 	OperThreadNode* node;
RunFuncOperThreadParam94 	void RunFunc() const
95 	{
96 		if ( this->func )
97 		{
98 			this->func( this->node );
99 		}
100 	}
101 };
102 
__123___OperThread(void * param)103 void* __123___OperThread( void* param )
104 {
105 	if ( !param ) { return nullptr; }
106 
107 	clPtr<OperThreadParam> pTp( ( OperThreadParam* )param );
108 
109 	// release the reference added before thread start
110 	pTp->DecRefCount();
111 
112 	try
113 	{
114 		pTp->RunFunc();
115 	}
116 	catch ( ... )
117 	{
118 		fprintf( stderr, "__123___OperThread(): exception in OperThread!!!\n" );
119 	}
120 
121 	MutexLock lock( &operMutex );
122 	MutexLock lockNode( &pTp->node->mutex );
123 
124 	if ( pTp->node->stopped )
125 	{
126 		if ( pTp->node->prev )
127 		{
128 			pTp->node->prev->next = pTp->node->next;
129 		}
130 		else
131 		{
132 			operStopList = pTp->node->next;
133 		}
134 
135 		if ( pTp->node->next )
136 		{
137 			pTp->node->next->prev = pTp->node->prev;
138 		}
139 	}
140 	else
141 	{
142 		ASSERT( pTp->node->win );
143 	}
144 
145 	if ( pTp->node->win )
146 	{
147 		// reset pointer to the Node in corresponding ThreadWin since we are going to delete it
148 		pTp->node->win->tNode = nullptr;
149 	}
150 
151 	pTp->node->stopped = true; //!!!
152 	lockNode.Unlock(); //!!!
153 
154 #ifdef _DEBUG
155 	printf( "stop: %s\n", pTp->node->threadInfo.data( ) );
156 #endif
157 
158 	delete( pTp->node );
159 
160 	pTp->node = nullptr;
161 
162 	return nullptr;
163 }
164 
165 
166 
RunNewThread(const char * info,OperThreadFunc f,void * data)167 void OperThreadWin::RunNewThread( const char* info, OperThreadFunc f, void* data )
168 {
169 	StopThread();
170 
171 	clPtr<OperThreadParam> param = new OperThreadParam;
172 	tNode = new OperThreadNode( this, info, data );
173 
174 	param->func = f;
175 	param->node = tNode;
176 
177 	MutexLock lock( &operMutex );
178 
179 	try
180 	{
181 		int n = NewThreadID();
182 //printf("TN=%i\n", n);
183 		param->IncRefCount();
184 		ThreadCreate( n, __123___OperThread, param.ptr() );
185 		threadId = n;
186 		param.drop(); //!!!
187 	}
188 	catch ( ... )
189 	{
190 		delete tNode;
191 		tNode = 0;
192 	}
193 }
194 
ThreadSignal(int id,int data)195 void OperThreadWin::ThreadSignal( int id, int data )
196 {
197 	if ( data == 1 )
198 	{
199 		MutexLock lock( &operMutex );
200 
201 		if ( !tNode ) { return; } //уже остановлен и каллбаку послан согнал с отрицательным результатом
202 
203 		ASSERT( !cbExecuted );
204 		cbExecuted = true;
205 		OperThreadNode* p = tNode;
206 		lock.Unlock();
207 
208 		try
209 		{
210 			p->cbRet = p->cbFunc( p->cbData );
211 		}
212 		catch ( ... )
213 		{
214 			fprintf( stderr, "!!! exception in OperThreadWin::ThreadSignal !!!\n" );
215 		}
216 
217 		lock.Lock();
218 		cbExecuted = false;
219 		p->cbCond.Signal();
220 	}
221 	else
222 	{
223 		OperThreadSignal( data );
224 	}
225 }
226 
OperThreadSignal(int data)227 void OperThreadWin::OperThreadSignal( int data ) {}
OperThreadStopped()228 void OperThreadWin::OperThreadStopped() {}
229 
ThreadStopped(int id,void * data)230 void OperThreadWin::ThreadStopped( int id, void* data )
231 {
232 	MutexLock lock( &operMutex );
233 
234 //printf("stopped TN=%i\n", id);
235 	if ( threadId == id )
236 	{
237 		threadId = -1;
238 		lock.Unlock(); //!!!!!!!
239 		OperThreadStopped();
240 	}
241 }
242 
~OperThreadWin()243 OperThreadWin::~OperThreadWin()
244 {
245 	if ( cbExecuted ) { fprintf( stderr, "!!! BUG ~OperThreadWin\n" ); }
246 
247 	StopThread();
248 }
249