YARP
Yet Another Robot Platform
 
Loading...
Searching...
No Matches
RunProcManager.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2006-2021 Istituto Italiano di Tecnologia (IIT)
3 * SPDX-FileCopyrightText: 2006-2010 RobotCub Consortium
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
9
10#include <yarp/os/Network.h>
11#include <yarp/os/RpcClient.h>
12#include <yarp/os/Semaphore.h>
13#include <yarp/os/Time.h>
14
16
17#include <cstring>
18
19#define WAIT() { RUNLOG("<<<mutex.lock()") mutex.lock(); RUNLOG(">>>mutex.lock()") }
20#define POST() { RUNLOG("<<<mutex.unlock()") mutex.unlock(); RUNLOG(">>>mutex.unlock()") }
21
22#if defined(_WIN32)
23 #include <process.h>
24
25 #define SIGKILL 9
26 static bool KILL(HANDLE handle)
27 {
28 BOOL bRet=TerminateProcess(handle, 0);
29
30 CloseHandle(handle);
31 fprintf(stderr, "brutally terminated by TerminateProcess\n");
32
33 return bRet?true:false;
34 }
35 static bool TERMINATE(PID pid);
36 #define CLOSE(h) CloseHandle(h)
37 #ifndef __GNUC__
38 static DWORD WINAPI ZombieHunter(__in LPVOID lpParameter)
39 #else
40 static DWORD WINAPI ZombieHunter(LPVOID lpParameter)
41 #endif
42 {
43 YarpRunInfoVector* pProcessVector=(YarpRunInfoVector*)lpParameter;
44
45 while (true)
46 {
47 DWORD nCount=0;
48 HANDLE* aHandlesVector = nullptr;
49 pProcessVector->GetHandles(aHandlesVector, nCount);
50
51 if (nCount)
52 {
53 WaitForMultipleObjects(nCount, aHandlesVector, FALSE, INFINITE);
54 delete [] aHandlesVector;
55 }
56 else
57 {
58 //hZombieHunter = nullptr;
59
60 return 0;
61 }
62 }
63
64 return 0;
65 }
66#else // LINUX
67 #include <unistd.h>
68 #include <fcntl.h>
69
70 int CLOSE(int h)
71 {
72 int ret=(close(h)==0);
73 return ret;
74 }
75
76 int SIGNAL(int pid, int signum)
77 {
78 int ret=!yarp::os::impl::kill(pid, signum);
79 return ret;
80 }
81#endif // LINUX
82
83YarpRunProcInfo::YarpRunProcInfo(std::string& alias, std::string& on, PID pidCmd, HANDLE handleCmd, bool hold)
84{
85 mAlias=alias;
86 mOn=on;
87 mPidCmd=pidCmd;
88 mCleanCmd=false;
89 mHandleCmd=handleCmd;
90 mHold=hold;
91}
92
94{
95#if defined(_WIN32)
96 if (signum==SIGKILL)
97 {
98 if (mHandleCmd)
99 {
100 bool ret=KILL(mHandleCmd);
101 return ret;
102 }
103 }
104 else
105 {
106 if (mPidCmd)
107 {
108 bool ret=TERMINATE(mPidCmd);
109 return ret;
110 }
111 }
112#else
113 if (mPidCmd && !mHold)
114 {
115 bool ret=SIGNAL(mPidCmd, signum);
116 return ret;
117 }
118#endif
119
120 return true;
121}
122
124{
125 if (!mPidCmd)
126 {
127 return false;
128 }
129#if defined(_WIN32)
130 DWORD status;
131 RUNLOG("<<<GetExitCodeProcess(mHandleCmd, &status)")
132 bool ret=(::GetExitCodeProcess(mHandleCmd, &status) && status==STILL_ACTIVE);
133 RUNLOG(">>>GetExitCodeProcess(mHandleCmd, &status)")
134 return ret;
135#else
136 bool ret=!yarp::os::impl::kill(mPidCmd, 0);
137 return ret;
138#endif
139}
140
142{
143#if !defined(_WIN32)
144 if (!mCleanCmd && yarp::os::impl::waitpid(mPidCmd, nullptr, WNOHANG) == mPidCmd)
145 {
146 fprintf(stderr, "CLEANUP cmd %d\n", mPidCmd);
147 mCleanCmd=true;
148 }
149
150 return mCleanCmd;
151#else
152 return true;
153#endif
154}
155
157{
158 m_nProcesses=0;
159 m_pStdioMate = nullptr;
160 for (auto & i : m_apList)
161 {
162 i = nullptr;
163 }
164}
165
167{
168 WAIT()
169
170 for (auto & i : m_apList)
171 {
172 if (i)
173 {
174 delete i;
175 i = nullptr;
176 }
177 }
178
179#if defined(_WIN32)
180 if (hZombieHunter)
181 {
182 HANDLE hkill=hZombieHunter;
183 hZombieHunter = nullptr;
184 TerminateThread(hkill, 0);
185 }
186#endif
187
188 POST()
189}
190
192{
193 WAIT()
194
196 {
197 fprintf(stderr, "ERROR: maximum process limit reached\n");
198 POST()
199 return false;
200 }
201
202#if defined(_WIN32)
203 if (hZombieHunter)
204 {
205 HANDLE hkill=hZombieHunter;
206 hZombieHunter = nullptr;
207 TerminateThread(hkill, 0);
208 }
209#endif
210
211 m_apList[m_nProcesses++]=process;
212
213#if defined(_WIN32)
214 hZombieHunter=CreateThread(0, 0, ZombieHunter, this, 0, 0);
215#endif
216
217 POST()
218 return true;
219}
220
221int YarpRunInfoVector::Signal(std::string& alias, int signum)
222{
223 WAIT()
224
225 auto* *aKill=new YarpRunProcInfo*[m_nProcesses];
226 int nKill=0;
227
228 for (int i=0; i<m_nProcesses; ++i)
229 {
230 if (m_apList[i] && m_apList[i]->Match(alias)) // && m_apList[i]->IsActive())
231 {
232 aKill[nKill++]=m_apList[i];
233 }
234 }
235
236 POST()
237
238 for (int k=0; k<nKill; ++k)
239 {
240 fprintf(stderr, "SIGNAL %s (%d)\n", aKill[k]->mAlias.c_str(), aKill[k]->mPidCmd);
241 aKill[k]->Signal(signum);
242 }
243
244 delete [] aKill;
245
246 return nKill;
247}
248
250{
251 WAIT()
252
253 auto* *aKill=new YarpRunProcInfo*[m_nProcesses];
254 int nKill=0;
255
256 for (int i=0; i<m_nProcesses; ++i)
257 {
258 if (m_apList[i] && m_apList[i]->IsActive())
259 {
260 aKill[nKill++]=m_apList[i];
261 }
262 }
263
264 POST()
265
266 for (int k=0; k<nKill; ++k)
267 {
268 fprintf(stderr, "SIGNAL %s (%d)\n", aKill[k]->mAlias.c_str(), aKill[k]->mPidCmd);
269 aKill[k]->Signal(signum);
270 }
271
272 delete [] aKill;
273
274 return nKill;
275}
276
277#if defined(_WIN32)
278void YarpRunInfoVector::GetHandles(HANDLE* &lpHandles, DWORD &nCount)
279{
280 WAIT()
281
282 if (lpHandles) delete [] lpHandles;
283
284 if (m_nProcesses>0) lpHandles=new HANDLE[m_nProcesses];
285
286 for (int i=0; i<m_nProcesses; ++i) if (m_apList[i])
287 {
288 if (!m_apList[i]->IsActive())
289 {
290 fprintf(stderr, "CLEANUP %s (%d)\n", m_apList[i]->mAlias.c_str(), m_apList[i]->mPidCmd);
291 fflush(stderr);
292
293 m_apList[i]->Clean();
294 delete m_apList[i];
295 m_apList[i]=0;
296 }
297 }
298
299 Pack();
300
301 for (int i=0; i<m_nProcesses; ++i)
302 {
303 lpHandles[nCount+i]=m_apList[i]->mHandleCmd;
304 }
305
306 nCount+=m_nProcesses;
307
308 POST()
309}
310
311#else
312
314{
315 bool bFound=false;
316
317 YarpRunProcInfo *pZombie = nullptr;
318
319 WAIT()
320
321 for (int i=0; i<m_nProcesses; ++i)
322 {
323 if (m_apList[i] && m_apList[i]->Clean(zombie, pZombie))
324 {
325 bFound=true;
326 if (pZombie) {
327 m_apList[i] = nullptr;
328 }
329 break;
330 }
331 }
332
333 Pack();
334
335 POST()
336
337 if (pZombie)
338 {
339 pZombie->finalize();
340 delete pZombie;
341 }
342
343 return bFound;
344}
345#endif
346
348{
349 WAIT()
350
351 yarp::os::Bottle ps, line, grp;
352
353 for (int i = 0; i < m_nProcesses; ++i) {
354 if (m_apList[i]) {
355 line.clear();
356
357 grp.clear();
358 grp.addString("pid");
359 grp.addInt32(m_apList[i]->mPidCmd);
360 line.addList() = grp;
361
362 grp.clear();
363 grp.addString("tag");
364 grp.addString(m_apList[i]->mAlias.c_str());
365 line.addList() = grp;
366
367 grp.clear();
368 grp.addString("status");
369 grp.addString(m_apList[i]->IsActive() ? "running" : "zombie");
370 line.addList() = grp;
371
372 grp.clear();
373 grp.addString("cmd");
374 grp.addString(m_apList[i]->mCmd.c_str());
375 line.addList() = grp;
376
377 grp.clear();
378 grp.addString("env");
379 grp.addString(m_apList[i]->mEnv.c_str());
380 line.addList() = grp;
381
382 ps.addList() = line;
383 }
384 }
385
386 POST()
387
388 return ps;
389}
390
391bool YarpRunInfoVector::IsRunning(std::string &alias)
392{
393 WAIT()
394
395 for (int i=0; i<m_nProcesses; ++i)
396 {
397 if (m_apList[i] && m_apList[i]->Match(alias))
398 {
399 if (m_apList[i]->IsActive())
400 {
401 POST()
402 return true;
403 }
404 else
405 {
406 POST()
407 return false;
408 }
409 }
410 }
411
412 POST()
413
414 return false;
415}
416
418{
419 int tot=0;
420
421 for (int i=0; i<m_nProcesses; ++i)
422 {
423 if (m_apList[i])
424 {
425 m_apList[tot++]=m_apList[i];
426 }
427 }
428
429 for (int i=tot; i<m_nProcesses; ++i)
430 {
431 m_apList[i]=nullptr;
432 }
433
434 m_nProcesses=tot;
435}
436
438 std::string& on,
439 std::string& stdio,
440 PID pidCmd,
441 PID pidStdout,
442 FDESC readFromPipeCmdToStdout,
443 FDESC writeToPipeCmdToStdout,
444 HANDLE handleCmd,
445 bool hold)
446 :
447YarpRunProcInfo(alias, on, pidCmd, handleCmd, hold)
448{
449 mPidStdin=0;
450 mPidStdout=pidStdout;
451 mStdio=stdio;
452 mStdioUUID="";
453 mStdioVector = nullptr;
454
457 mReadFromPipeCmdToStdout=readFromPipeCmdToStdout;
458 mWriteToPipeCmdToStdout=writeToPipeCmdToStdout;
459
460 mKillingCmd=false;
461 mKillingStdio=false;
462 mKillingStdin=false;
463 mKillingStdout=false;
464
465 mCleanStdin=true;
466 mCleanStdout=false;
467}
468
470 std::string& on,
471 std::string& stdio,
472 PID pidCmd,
473 std::string& stdioUUID,
474 YarpRunInfoVector* stdioVector,
475 PID pidStdin,
476 PID pidStdout,
477 FDESC readFromPipeStdinToCmd,
478 FDESC writeToPipeStdinToCmd,
479 FDESC readFromPipeCmdToStdout,
480 FDESC writeToPipeCmdToStdout,
481 HANDLE handleCmd,
482 bool hold)
483 :
484YarpRunProcInfo(alias, on, pidCmd, handleCmd, hold)
485{
486 mPidStdin=pidStdin;
487 mPidStdout=pidStdout;
488 mStdio=stdio;
489 mStdioUUID=stdioUUID;
490
491 mStdioVector=stdioVector;
492
493 mReadFromPipeStdinToCmd=readFromPipeStdinToCmd;
494 mWriteToPipeStdinToCmd=writeToPipeStdinToCmd;
495 mReadFromPipeCmdToStdout=readFromPipeCmdToStdout;
496 mWriteToPipeCmdToStdout=writeToPipeCmdToStdout;
497
498 mKillingCmd=false;
499 mKillingStdio=false;
500 mKillingStdin=false;
501 mKillingStdout=false;
502
503 mCleanStdin=false;
504 mCleanStdout=false;
505}
506
508{
509#if defined(_WIN32)
510 if (mPidCmd)
511 {
512 mPidCmd=0;
513
518
523
524 if (mPidStdin) TERMINATE(mPidStdin);
525
526 if (mPidStdout) TERMINATE(mPidStdout);
527
529 }
530
531 return false;
532
533#else
534
535 if (!mCleanCmd && yarp::os::impl::waitpid(mPidCmd, nullptr, WNOHANG) == mPidCmd)
536 {
537 fprintf(stderr, "CLEANUP cmd %d\n", mPidCmd);
538 mCleanCmd=true;
539 }
540
541 if (!mCleanStdin && yarp::os::impl::waitpid(mPidStdin, nullptr, WNOHANG) == mPidStdin)
542 {
543 fprintf(stderr, "CLEANUP stdin %d\n", mPidStdin);
544 mCleanStdin=true;
545 }
546
547 if (!mCleanStdout && yarp::os::impl::waitpid(mPidStdout, nullptr, WNOHANG) == mPidStdout)
548 {
549 fprintf(stderr, "CLEANUP stdout %d\n", mPidStdout);
550 mCleanStdout=true;
551 }
552
554 {
555 return false;
556 }
557
558 if (!mKillingStdio)
559 {
560 mKillingStdio=true;
561
564 }
567 }
570 }
573 }
574
579 }
580
581 if (!mCleanCmd && !mKillingCmd)
582 {
583 yarp::os::impl::kill(mPidCmd, SIGTERM);
584 mKillingCmd=true;
585 }
586
587 if (!mCleanStdin && !mKillingStdin)
588 {
589 yarp::os::impl::kill(mPidStdin, SIGTERM);
590 mKillingStdin=true;
591 }
592
594 {
595 yarp::os::impl::kill(mPidStdout, SIGTERM);
596 mKillingStdout=true;
597 }
598
600 {
601 return true;
602 }
603
604 return false;
605#endif
606}
607
609{
610 if (!mStdioVector) {
611 return;
612 }
613
614 if (mOn==mStdio)
615 {
616 mStdioVector->Signal(mAlias, SIGTERM);
617 }
618 else
619 {
621 msg.fromString(std::string("(killstdio ")+mAlias+")");
622 yarp::run::Run::sendMsg(msg, mStdio);
623 }
624}
625
629
630#if defined(_WIN32)
631
632#define TA_FAILED 0
633#define TA_SUCCESS_CLEAN 1
634#define TA_SUCCESS_KILL 2
635
636class TerminateParams
637{
638public:
639 TerminateParams(DWORD id)
640 {
641 nWin=0;
642 dwID=id;
643 }
644
645 ~TerminateParams(){}
646
647 int nWin;
648 DWORD dwID;
649};
650
651BOOL CALLBACK TerminateAppEnum(HWND hwnd, LPARAM lParam)
652{
653 TerminateParams* params=(TerminateParams*)lParam;
654
655 DWORD dwID;
656 GetWindowThreadProcessId(hwnd, &dwID) ;
657
658 if (dwID==params->dwID)
659 {
660 params->nWin++;
661 PostMessage(hwnd, WM_CLOSE, 0, 0);
662 }
663
664 return TRUE;
665}
666
667/*----------------------------------------------------------------
668Purpose:
669Shut down a 32-Bit Process
670
671Parameters:
672dwPID
673Process ID of the process to shut down.
674----------------------------------------------------------------*/
675bool TERMINATE(PID dwPID)
676{
677 HANDLE hProc;
678
679 // If we can't open the process with PROCESS_TERMINATE rights,
680 // then we give up immediately.
681 hProc=OpenProcess(SYNCHRONIZE|PROCESS_TERMINATE, FALSE, dwPID);
682
683 if (hProc == nullptr)
684 {
685 return false;
686 }
687
688 // TerminateAppEnum() posts WM_CLOSE to all windows whose PID
689 // matches your process's.
690
691 TerminateParams params(dwPID);
692
693 EnumWindows((WNDENUMPROC)TerminateAppEnum, (LPARAM)&params);
694
695 if (params.nWin)
696 {
697 fprintf(stderr, "%d terminated by WM_CLOSE (sending anyway CTRL_C_EVENT/CTRL_BREAK_EVENT)\n", dwPID);
698 }
699 else
700 {
701 //GenerateConsoleCtrlEvent(CTRL_C_EVENT, dwPID);
702 //GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, dwPID);
703 fprintf(stderr, "%d terminated by CTRL_C_EVENT/CTRL_BREAK_EVENT\n", dwPID);
704 }
705
706 GenerateConsoleCtrlEvent(CTRL_C_EVENT, dwPID);
707 GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, dwPID);
708
709 CloseHandle(hProc);
710
711 return true;
712}
713
714#endif
bool ret
#define RUNLOG(msg)
int SIGNAL(int pid, int signum)
int CLOSE(int h)
#define POST()
#define WAIT()
int SIGNAL(int pid, int signum)
int CLOSE(int h)
int FDESC
pid_t PID
YarpRunInfoVector * mStdioVector
YarpRunCmdWithStdioInfo(std::string &alias, std::string &on, std::string &stdio, PID pidCmd, PID pidStdout, FDESC readFromPipeCmdToStdout, FDESC writeToPipeCmdToStdout, HANDLE handleCmd, bool hold)
int Signal(std::string &alias, int signum)
bool CleanZombie(int zombie)
static const int MAX_PROCESSES
int Killall(int signum)
yarp::os::Bottle PS()
YarpRunInfoVector * m_pStdioMate
YarpRunProcInfo * m_apList[MAX_PROCESSES]
bool IsRunning(std::string &alias)
bool Add(YarpRunProcInfo *process)
virtual void finalize()
std::string mAlias
YarpRunProcInfo(std::string &alias, std::string &on, PID pidCmd, HANDLE handleCmd, bool hold)
virtual bool Signal(int signum)
virtual bool Clean()
virtual bool Clean(PID pid, YarpRunProcInfo *&pRef)
virtual bool IsActive()
A simple collection of objects that can be described and transmitted in a portable way.
Definition Bottle.h:64
void fromString(const std::string &text)
Initializes bottle from a string.
Definition Bottle.cpp:204
Bottle & addList()
Places an empty nested list in the bottle, at the end of the list.
Definition Bottle.cpp:182
void clear()
Empties the bottle of any objects it contains.
Definition Bottle.cpp:121
void addInt32(std::int32_t x)
Places a 32-bit integer in the bottle, at the end of the list.
Definition Bottle.cpp:140
void addString(const char *str)
Places a string in the bottle, at the end of the list.
Definition Bottle.cpp:170
A mini-server for performing network communication in the background.