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