OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [host/] [tools/] [Utils/] [common/] [Subprocess.cpp] - Blame information for rev 790

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 786 skrzyp
// ####ECOSHOSTGPLCOPYRIGHTBEGIN####                                        
2
// -------------------------------------------                              
3
// This file is part of the eCos host tools.                                
4
// Copyright (C) 1998, 1999, 2000, 2004 Free Software Foundation, Inc.      
5
//
6
// This program is free software; you can redistribute it and/or modify     
7
// it under the terms of the GNU General Public License as published by     
8
// the Free Software Foundation; either version 2 or (at your option) any   
9
// later version.                                                           
10
//
11
// This program is distributed in the hope that it will be useful, but      
12
// WITHOUT ANY WARRANTY; without even the implied warranty of               
13
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU        
14
// General Public License for more details.                                 
15
//
16
// You should have received a copy of the GNU General Public License        
17
// along with this program; if not, write to the                            
18
// Free Software Foundation, Inc., 51 Franklin Street,                      
19
// Fifth Floor, Boston, MA  02110-1301, USA.                                
20
// -------------------------------------------                              
21
// ####ECOSHOSTGPLCOPYRIGHTEND####                                          
22
//===========================================================================
23
//===========================================================================
24
//#####DESCRIPTIONBEGIN####
25
//
26
// Author(s):   sdf
27
// Contact(s):  sdf
28
// Date:                1998/08/11
29
// Version:             0.01
30
// Purpose:     
31
// Description: This is the implementation of the class which allows for spawning subprocesses
32
//
33
// Requires:    
34
// Provides:    
35
// See also:    
36
// Known bugs:  
37
// Usage:       
38
//
39
//####DESCRIPTIONEND####
40
//
41
//===========================================================================
42
 
43
// define _GNU_SOURCE to ensure that stdlib.h provides Unix98 PTY declarations
44
#define _GNU_SOURCE
45
 
46
#include "eCosTrace.h"
47
#include "Subprocess.h"
48
#ifdef _WIN32
49
  #include <tlhelp32.h>
50
 
51
  HINSTANCE CSubprocess::hInstLib1 = VER_PLATFORM_WIN32_NT==CSubprocess::GetPlatform()?LoadLibrary(_T("PSAPI.DLL")):LoadLibrary(_T("Kernel32.DLL")) ;
52
  HINSTANCE CSubprocess::hInstLib2 = VER_PLATFORM_WIN32_NT==CSubprocess::GetPlatform()?LoadLibrary(_T("NTDLL.DLL")):NULL;
53
 
54
#endif
55
 
56
//#define CloseHandle(x) TRACE(_T("CSubprocess::CloseHandle %x\n"),x);::CloseHandle(x)
57
 
58
const unsigned int CSubprocess::PROCESS_KILL_EXIT_CODE=0xCCFFCCFF;
59
 
60
CSubprocess::CSubprocess(bool bAutoDelete):
61
  m_pfnContinue(DefaultContinuationFunc),
62
  m_pContinuationFuncParam(0),
63
  m_bAutoDelete(bAutoDelete),
64
  m_bThreadTerminated(true),
65
  m_bVerbose(false),
66
  m_nExitCode(-1),
67
  m_idProcess(0),
68
  m_pLogparam(0),
69
  m_pfnLogfunc(0),
70
  m_bKillThread(false)
71
{
72
#ifdef _WIN32
73
  m_hProcess=0;
74
#endif
75
}
76
 
77
CSubprocess::~CSubprocess()
78
{
79
  Kill();
80
  if(!CeCosThreadUtils::WaitFor(m_bThreadTerminated,1000)){
81
    m_bKillThread=true;
82
    CeCosThreadUtils::WaitFor(m_bThreadTerminated);
83
  }
84
#ifdef _WIN32
85
  if(m_hProcess){
86
    CloseHandle(m_hProcess);
87
  }
88
#endif
89
}
90
 
91
bool CSubprocess::Run(LogFunc *pfnLog,void * pLogparam, LPCTSTR pszCmd,bool bBlock/*=true*/)
92
{
93
  bool rc;
94
  if(!m_bThreadTerminated){
95
    rc=false;
96
  } else {
97
    m_pfnLogfunc=pfnLog;
98
    m_pLogparam=pLogparam;
99
#ifdef _WIN32 
100
    // UNIX does it from the thread func.  WIN32 could too, but it's nice to know at the time 
101
    // of calling run whether the process is successfully created.
102
    if(m_hProcess){
103
      // Normally done in the dtor
104
      CloseHandle(m_hProcess);
105
    }
106
    rc=CreateProcess(pszCmd);
107
#else 
108
    m_strCmd=pszCmd;
109
    rc=true;
110
#endif
111
    if(rc){
112
      m_bKillThread=false;
113
      if(bBlock){
114
        // When using RunThread, the manipulation of this Boolean is taken care of.
115
        // Here we must do it ourselves.
116
        m_bThreadTerminated=false;
117
        ThreadFunc();
118
        m_bThreadTerminated=true;
119
      } else {
120
        CeCosThreadUtils::RunThread(SThreadFunc,this,&m_bThreadTerminated,String::SFormat(_T("subprocess %d read"),m_idProcess));
121
      }
122
    }
123
  }
124
  return rc;
125
}
126
 
127
#ifdef _WIN32
128
bool CSubprocess::CreateProcess(LPCTSTR pszCmdline)
129
{
130
 
131
  STARTUPINFO   si;                    // For CreateProcess call
132
  HANDLE        hrPipe,hwPipe,hwPipe2,m_hrPipeTemp,m_hwPipeTemp;
133
  // Create the anonymous pipe
134
 
135
  SECURITY_ATTRIBUTES saPipe;          // Security for anonymous pipe
136
  saPipe.nLength = sizeof(SECURITY_ATTRIBUTES);
137
  saPipe.lpSecurityDescriptor = NULL;
138
  saPipe.bInheritHandle = true;
139
 
140
  ::CreatePipe(&m_hrPipeTemp,&hwPipe,&saPipe,10240);
141
 
142
  // In most cases you can get away with using the same anonymous
143
  // pipe write handle for both the child's standard output and
144
  // standard error, but this may cause problems if the child app
145
  // explicitly closes one of its standard output or error handles. If
146
  // that happens, the anonymous pipe will close, since the child's
147
  // standard output and error handles are really the same handle. The
148
  // child won't be able to write to the other write handle since the
149
  // pipe is now gone, and parent reads from the pipe will return
150
  // ERROR_BROKEN_PIPE and child output will be lost. To solve this
151
  // problem, simply duplicate the write end of the pipe to create
152
  // another distinct, separate handle to the write end of the pipe.
153
  // One pipe write handle will serve as standard out, the other as
154
  // standard error. Now *both* write handles must be closed before the
155
  // write end of the pipe actually closes.
156
 
157
  ::DuplicateHandle(::GetCurrentProcess(),                      // Source process
158
    hwPipe,                     // Handle to duplicate
159
    ::GetCurrentProcess(),   // Destination process
160
    &hwPipe2,               // New handle, used as stderr by child 
161
    0,                     // New access flags - ignored since DUPLICATE_SAME_ACCESS
162
    true,                  // It's inheritable
163
    DUPLICATE_SAME_ACCESS);
164
 
165
  ::CreatePipe(&hrPipe,&m_hwPipeTemp,&saPipe,10240);
166
 
167
 
168
  // Create new output read handle and the input write handles, setting
169
  // the Properties to FALSE. Otherwise, the child inherits the
170
  // properties and, as a result, non-closeable handles to the pipes
171
  // are created.
172
  DuplicateHandle(GetCurrentProcess(),m_hrPipeTemp,
173
                       GetCurrentProcess(),
174
                       &m_hrPipe, // Address of new handle.
175
                       0,FALSE, // Make it uninheritable.
176
                       DUPLICATE_SAME_ACCESS);
177
 
178
  DuplicateHandle(GetCurrentProcess(),m_hwPipeTemp,
179
                       GetCurrentProcess(),
180
                       &m_hwPipe, // Address of new handle.
181
                       0,FALSE, // Make it uninheritable.
182
                       DUPLICATE_SAME_ACCESS);
183
 
184
  // Close inheritable copies of the handles we do not want to be inherited:
185
  CloseHandle(m_hrPipeTemp);
186
  CloseHandle(m_hwPipeTemp);
187
 
188
 
189
  memset(&si, 0, sizeof(si));
190
  si.cb = sizeof(si);
191
 
192
  si.hStdOutput = hwPipe;
193
  si.hStdError =  hwPipe2;
194
  si.hStdInput =  hrPipe;
195
  si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
196
  si.wShowWindow = SW_SHOW;
197
 
198
  LPCTSTR pszDir;
199
  if(m_strDir.empty()){
200
    pszDir=NULL; // current directory
201
  } else {
202
    pszDir=m_strDir;
203
  }
204
 
205
  PROCESS_INFORMATION pi;
206
  String strCmd(pszCmdline);
207
 
208
  String strOrigpath;
209
  if(!m_strPath.empty()){
210
          int nSize=GetEnvironmentVariable(_T("PATH"), NULL, 0);
211
          if(nSize>0){
212
      GetEnvironmentVariable(_T("PATH"),strOrigpath.GetBuffer(nSize),nSize);
213
      strOrigpath.ReleaseBuffer();
214
      SetEnvironmentVariable(_T("PATH"),m_strPath);
215
    }
216
  }
217
 
218
  bool rc=(TRUE==::CreateProcess(NULL,strCmd.GetBuffer(),NULL,NULL,true,DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP,NULL,pszDir,&si,&pi));
219
 
220
  if(!m_strPath.empty()){
221
    SetEnvironmentVariable(_T("PATH"),strOrigpath);
222
  }
223
 
224
  m_nErr=GetLastError();
225
 
226
  strCmd.ReleaseBuffer();
227
 
228
  if(rc){
229
    m_idProcess=pi.dwProcessId;
230
    m_hProcess=pi.hProcess;
231
    if(m_bVerbose){
232
      Output(String::SFormat(_T("*** Process %d created \"%s\"\n"),m_idProcess,pszCmdline));
233
    }
234
    TRACE(String::SFormat(_T("Process %d created \"%s\"\n"),m_idProcess,pszCmdline));
235
    m_nExitCode=STILL_ACTIVE;
236
    CloseHandle(pi.hThread);
237
  } else {
238
    m_idProcess=0;
239
    if(m_bVerbose){
240
      Output(String::SFormat(_T("*** Failed to create process \"%s\" %s\n"),pszCmdline,(LPCTSTR)ErrorString()));
241
    }
242
    TRACE(String::SFormat(_T("Failed to create process \"%s\" %s\n"),pszCmdline,(LPCTSTR)ErrorString()));
243
    m_nExitCode=GetLastError();
244
    CloseHandle(m_hrPipe);m_hrPipe=INVALID_HANDLE_VALUE;
245
    CloseHandle(m_hwPipe);m_hwPipe=INVALID_HANDLE_VALUE;
246
  }
247
 
248
  CloseHandle(hrPipe);
249
  CloseHandle(hwPipe);
250
  CloseHandle(hwPipe2);
251
 
252
  return rc;
253
 
254
}
255
 
256
void CSubprocess::ThreadFunc()
257
{
258
 
259
  TRACE(_T("Reading from process %d\n"),m_idProcess);
260
 
261
  DWORD dwAvail;
262
 
263
  DWORD dwExitCode;
264
 
265
  while (!m_bKillThread && m_pfnContinue(m_pContinuationFuncParam) && ::PeekNamedPipe(m_hrPipe, NULL, 0, 0, &dwAvail, NULL)){
266
//TRACE(_T("P%d\n"),dwAvail);
267
    if(dwAvail){
268
      dwAvail=MIN(dwAvail,80); // Read a maximum of 80 characters at a time
269
      DWORD dwRead;
270
      char *buf=new char[dwAvail+1];
271
//TRACE(_T("R%d\n"),dwAvail);
272
      if(!::ReadFile(m_hrPipe, buf, dwAvail, &dwRead, NULL)){
273
        TRACE(_T("ReadFile returns false\n"));
274
        delete [] buf;
275
        break;
276
      }
277
      buf[dwRead]='\0';
278
      Output(String::CStrToUnicodeStr(buf));
279
      delete [] buf;
280
    }
281
    else if (!ProcessAlive())
282
    {
283
        TRACE(_T("m_bThreadTerminated=%d\n"),m_bThreadTerminated);
284
        break;
285
    }
286
    // Fix for hanging in an endless loop under Windows ME, by Bill Diehls <billabloke@yahoo.com>
287
    else if (::GetExitCodeProcess(m_hProcess, &dwExitCode) && dwExitCode!=STILL_ACTIVE)
288
    {
289
                break;
290
    }
291
    else
292
    {
293
      CeCosThreadUtils::Sleep(250);
294
    }
295
  }
296
 
297
  ::GetExitCodeProcess(m_hProcess, &dwExitCode);
298
  m_nExitCode=dwExitCode;
299
 
300
#ifdef _DEBUG
301
  String str;
302
  switch(dwExitCode){
303
    case STILL_ACTIVE:
304
      str=_T("still alive");
305
      if(m_bKillThread){
306
        str+=_T(" - requested to stop reading");
307
      }
308
      break;
309
    case PROCESS_KILL_EXIT_CODE:
310
      str=_T("killed");
311
      break;
312
    default:
313
      str.Format(_T("terminated rc=%d"),dwExitCode);
314
      break;
315
  }
316
  TRACE(_T("Finished reading from process %d (%s)\n"),m_idProcess,(LPCTSTR)str);
317
#endif
318
 
319
  CloseHandle(m_hrPipe);m_hrPipe=INVALID_HANDLE_VALUE;
320
  CloseHandle(m_hwPipe);m_hwPipe=INVALID_HANDLE_VALUE;
321
 
322
  if(m_bAutoDelete){
323
    m_bThreadTerminated=true; // or else the dtor will block
324
    delete this;
325
  }
326
}
327
 
328
#else // UNIX
329
 
330
bool CSubprocess::CreateProcess(LPCTSTR pszCmdline)
331
{
332
  m_idProcess=0;
333
  int fdchild=-1; // the file descriptor for the child (slave) half of the pseudo-tty pair
334
 
335
  // Try the Unix98 scheme to get a pseudo-tty pair
336
  String strMasterTty("/dev/ptmx"), strChildTty;
337
  m_tty=open(strMasterTty, O_RDWR | O_NOCTTY);
338
  if (-1!=m_tty) {
339
    if ((0 == grantpt(m_tty)) && (0 == unlockpt(m_tty))) {
340
      strChildTty = ptsname(m_tty);
341
      if (!strChildTty.empty()) {
342
        fdchild = open(strChildTty, O_RDWR);
343
      }
344
    }
345
    if (-1==fdchild) {
346
      close(m_tty);
347
      m_tty=fdchild=-1;
348
    } else {
349
      VTRACE("opened %s - fd=%d\n",(LPCTSTR)strMasterTty,m_tty);
350
    }
351
  }
352
 
353
  if (-1==m_tty) {
354
    // Try the BSD scheme to get a free /dev/ptyp0 (master) and /dev/ttyp0 (slave) tty pair
355
    for(unsigned int c=0;c<64;c++){
356
      strMasterTty.Format("/dev/pty%c%x",'p'+c/16,c%16);
357
 
358
      m_tty=open(strMasterTty, O_RDWR | O_NOCTTY);
359
      if (-1!=m_tty) {
360
        strChildTty.Format("/dev/tty%c%x",'p'+c/16,c%16);
361
 
362
        fdchild = open(strChildTty, O_RDWR);
363
        if (-1==fdchild) {
364
          close(m_tty);
365
          m_tty=fdchild=-1;
366
        } else {
367
          VTRACE("opened %s - fd=%d\n",(LPCTSTR)strMasterTty,m_tty);
368
          break;
369
        }
370
      }
371
    }
372
  }
373
 
374
  if(-1==m_tty){
375
    ERROR(_T("Failed to get a pty\n"));
376
    return false;
377
  }
378
 
379
  TRACE(_T("Master pty %s (fd %d) slave pty %s (fd %d)\n"),(LPCTSTR)strMasterTty,m_tty,(LPCTSTR)strChildTty,fdchild);
380
 
381
  m_idProcess=fork();
382
 
383
  switch (m_idProcess) {
384
    // Fork failed
385
    case -1:
386
      TRACE(_T("Failed to create process - %s\n"),strerror(errno));
387
      m_idProcess=0;
388
      break;
389
    case 0:
390
      // Process is created (we're the child)
391
      {
392
        // Close all descriptors except the slave side of the pseudo-terminal
393
        for (int fd = 0; fd < (int) sysconf(_SC_OPEN_MAX); fd++) {
394
          if(fd!=fdchild){
395
            close(fd);
396
          }
397
        }
398
        setsid();
399
 
400
        dup2(fdchild, 0);
401
        dup2(fdchild, 1);
402
        dup2(fdchild, 2);
403
 
404
        close(fdchild);
405
 
406
        if(!m_strDir.empty()){
407
          if(0!=chdir(m_strDir)){
408
            if(m_bVerbose){
409
              fprintf(stderr,_T("*** Failed to change directory to %s\n"),(LPCTSTR)m_strDir);
410
            }
411
            exit (5);
412
          }
413
        }
414
        if(m_bVerbose){
415
          fprintf(stderr,_T("*** Process %d created \"%s\"\n"),m_idProcess,pszCmdline);
416
        }
417
 
418
        StringArray ar;
419
        int argc=String(pszCmdline).Chop(ar,_TCHAR(' '),true);
420
        TCHAR **argv=new TCHAR *[1+argc];
421
        for(int i=0;i<argc;i++){
422
          argv[i]=new TCHAR[1+strlen(ar[i])];
423
          strcpy(argv[i],ar[i]);
424
        }
425
        argv[argc]=0;
426
        if(!m_strPath.empty()){
427
          _tputenv(String::SFormat(_T("PATH=%s"),(LPCTSTR)m_strPath));
428
        }
429
        _texecvp(argv[0], argv);
430
      }
431
 
432
      fprintf(stderr,"exec error - %s\n",strerror(errno));
433
      exit(4);
434
 
435
    default:
436
      // Process is created (we're the parent)
437
      TRACE(_T("Closing fd %d\n"),fdchild);
438
      close(fdchild);
439
      TRACE(_T("Forked to create process %s - process id <%d>\n"), pszCmdline, m_idProcess);
440
      break;
441
  }
442
  return 0!=m_idProcess;
443
}
444
 
445
void CSubprocess::ThreadFunc()
446
{
447
  if(!CreateProcess(m_strCmd)){
448
    ERROR(_T("Failed to create process for %s\n"),(LPCTSTR)m_strCmd);
449
  } else {
450
    fcntl(m_tty,F_SETFL,O_NONBLOCK);
451
    int rc;
452
    do {
453
      TCHAR buf[4096];
454
      rc=read(m_tty, buf, sizeof(buf)-1);
455
      if(rc>=0){
456
        buf[rc]='\0';
457
      }
458
      switch(rc){
459
        case -1:
460
          if(EAGAIN==errno){
461
            CeCosThreadUtils::Sleep(250);
462
          } else {
463
              goto Done;
464
          }
465
          break;
466
        case 0:
467
          goto Done;
468
          continue;
469
        default:
470
          buf[rc]=_TCHAR('\0');
471
          Output(String::CStrToUnicodeStr(buf));
472
          continue;
473
      }
474
    } while(!m_bKillThread && m_pfnContinue(m_pContinuationFuncParam));
475
Done:
476
    TRACE(_T("Closing fd %d\n"),m_tty);
477
    close (m_tty);
478
 
479
    switch(waitpid(m_idProcess,&m_nExitCode,WNOHANG));
480
  }
481
 
482
  if(m_bAutoDelete){
483
    delete this;
484
  }
485
}
486
#endif
487
 
488
void CSubprocess::Output (LPCTSTR psz)
489
{
490
  m_pfnLogfunc(m_pLogparam,psz);
491
}
492
 
493
void CSubprocess::Send(LPCTSTR str)
494
{
495
  char *psz=String(str).GetCString();
496
  int nToWrite=strlen(psz);
497
  const char *c=psz;
498
  do {
499
#ifdef _WIN32
500
    DWORD dwWritten;
501
    if(!::WriteFile(m_hwPipe,psz,nToWrite,&dwWritten,0)){
502
      break;
503
    }
504
#else
505
    int dwWritten = write(m_tty, c, nToWrite);
506
    if(-1==dwWritten){
507
      break;
508
    }
509
#endif
510
    nToWrite-=(int)dwWritten;
511
    c+=(int)dwWritten;
512
  } while (nToWrite>0);
513
  //::FlushFileBuffers(m_hwPipe);
514
  delete [] psz;
515
}
516
 
517
bool CSubprocess::Kill(bool bRecurse)
518
{
519
TRACE(_T("CSubprocess::Kill pid %d recurse=%d\n"),m_idProcess,bRecurse);
520
  PInfoArray arPinfo;
521
  bool rc=false;
522
  if(m_idProcess && -1!=m_idProcess){
523
    // Start of with the easy one:
524
    if(bRecurse) {
525
      // Need to gather this information before we orphan our grandchildren:
526
      PSExtract(arPinfo);
527
    }
528
 
529
#ifdef _WIN32
530
 
531
    if(m_hProcess){
532
      TRACE(_T("Terminate process %s\n"),(LPCTSTR)Name(m_idProcess));
533
      rc=(TRUE==::TerminateProcess(m_hProcess,PROCESS_KILL_EXIT_CODE));
534
      // dtor's (or subsequent Run's) responsibility to close the handle
535
    }
536
 
537
#else
538
    rc=(0==kill(m_idProcess,SIGTERM));
539
    int status;
540
    waitpid(m_idProcess,&status,WNOHANG);
541
#endif
542
 
543
    if(bRecurse) {
544
      // kill process *and* its children
545
      // FIXME: needs to be top-down
546
      for(int i=0;i<(signed)arPinfo.size();i++){
547
        if(arPinfo[i].IsChildOf(m_idProcess)){
548
 
549
#ifdef _WIN32
550
          // begin hack
551
          const String strName(Name(arPinfo[i].PID));
552
          if(_tcsstr(strName,_T("eCosTest")) || _tcsstr(strName,_T("cmd.EXE")) || _tcsstr(strName,_T("CMD.EXE")) || arPinfo[i].PID==(signed)GetCurrentProcessId()){
553
            continue;
554
          }
555
          // end hack
556
          HANDLE hProcess=::OpenProcess(PROCESS_TERMINATE,false,arPinfo[i].PID);
557
          if(hProcess){
558
            TRACE(_T("Terminate process %s\n"),(LPCTSTR)Name(arPinfo[i].PID));
559
            rc&=(TRUE==::TerminateProcess(hProcess,PROCESS_KILL_EXIT_CODE));
560
            CloseHandle(hProcess);
561
          } else {
562
            rc=false;
563
          }
564
#else
565
          rc&=(0==kill(arPinfo[i].PID,SIGTERM));
566
          int status;
567
          waitpid(arPinfo[i].PID,&status,WNOHANG);
568
#endif
569
        }
570
      }
571
    }
572
  }
573
  return rc;
574
}
575
 
576
Time CSubprocess::CpuTime(bool bRecurse) const
577
{
578
  Time t=0;
579
  // kill process *and* its children
580
  // FIXME: needs to be top-down
581
 
582
#ifdef _WIN32
583
  __int64 ftCreation,ftExit,ftKernel,ftUser;
584
  if(m_hProcess && ::GetProcessTimes (m_hProcess,(FILETIME *)&ftCreation,(FILETIME *)&ftExit,(FILETIME *)&ftKernel,(FILETIME *)&ftUser)){
585
    t+=Time((ftKernel+ftUser)/10000);
586
  }
587
 
588
  if(bRecurse){
589
    PInfoArray arPinfo;
590
    PSExtract(arPinfo);
591
    if(m_idProcess && -1!=m_idProcess){
592
      for(int i=0;i<(signed)arPinfo.size();i++){
593
        if(arPinfo[i].IsChildOf(m_idProcess)){
594
          t+=arPinfo[i].tCpu;
595
        }
596
      }
597
    }
598
  }
599
#else
600
  PInfoArray arPinfo;
601
  PSExtract(arPinfo);
602
  for(int i=0;i<(signed)arPinfo.size();i++){
603
    if(arPinfo[i].PID==m_idProcess || arPinfo[i].IsChildOf(m_idProcess)){
604
      t+=arPinfo[i].tCpu;
605
    }
606
  }
607
#endif
608
  return t;
609
}
610
 
611
#ifdef _WIN32
612
bool CSubprocess::PSExtract(CSubprocess::PInfoArray &arPinfo)
613
{
614
  bool rc=false;
615
  arPinfo.clear();
616
  // If Windows NT:
617
  switch(GetPlatform()) {
618
  case VER_PLATFORM_WIN32_NT:
619
    if(hInstLib1) {
620
 
621
      // Get procedure addresses.
622
      static BOOL (WINAPI *lpfEnumProcesses)( DWORD *, DWORD cb, DWORD * ) = (BOOL(WINAPI *)(DWORD *,DWORD,DWORD*))GetProcAddress( hInstLib1, "EnumProcesses" ) ;
623
      if( lpfEnumProcesses) {
624
 
625
        if(hInstLib2) {
626
 
627
          static DWORD (WINAPI *lpfNtQueryInformationProcess)( HANDLE, int, void *, DWORD, LPDWORD ) =
628
            (DWORD(WINAPI *)(HANDLE, int, void *, DWORD, LPDWORD)) GetProcAddress( hInstLib2,"NtQueryInformationProcess" ) ;
629
 
630
          if(lpfNtQueryInformationProcess){
631
            DWORD dwMaxPids=256;
632
            DWORD dwPidSize;
633
            DWORD *arPids = NULL ;
634
            do {
635
              delete [] arPids;
636
              arPids=new DWORD[dwMaxPids];
637
            } while(lpfEnumProcesses(arPids, dwMaxPids, &dwPidSize) && dwPidSize/sizeof(DWORD)==dwMaxPids) ;
638
 
639
            if(dwPidSize/sizeof(DWORD)<dwMaxPids){
640
              rc=true;
641
              for( DWORD dwIndex = 0 ; (signed)dwIndex < dwPidSize/sizeof(DWORD); dwIndex++ ) {
642
                // Regardless of OpenProcess success or failure, we
643
                // still call the enum func with the ProcID.
644
                DWORD pid=arPids[dwIndex];
645
                HANDLE hProcess=::OpenProcess( PROCESS_QUERY_INFORMATION, FALSE, pid );
646
                if (hProcess ) {
647
                  struct {
648
                    DWORD ExitStatus; // receives process termination status
649
                    DWORD PebBaseAddress; // receives process environment block address
650
                    DWORD AffinityMask; // receives process affinity mask
651
                    DWORD BasePriority; // receives process priority class
652
                    ULONG UniqueProcessId; // receives process identifier
653
                    ULONG InheritedFromUniqueProcessId; // receives parent process identifier
654
                  } pbi;
655
                  memset( &pbi, 0, sizeof(pbi));
656
                  DWORD retLen;
657
                  __int64 ftCreation,ftExit,ftKernel,ftUser;
658
                  if(lpfNtQueryInformationProcess(hProcess, 0 /*ProcessBasicInformation*/, &pbi, sizeof(pbi), &retLen)>=0 &&
659
                    TRUE==::GetProcessTimes (hProcess,(FILETIME *)&ftCreation,(FILETIME *)&ftExit,(FILETIME *)&ftKernel,(FILETIME *)&ftUser)){
660
                    // The second test is important.  It excludes orphaned processes who appear to have been adopted by virtue of a new
661
                    // process having been created with the same ID as their original parent.
662
                    PInfo p;
663
                    p.PID=pid;
664
                    p.PPID=pbi.InheritedFromUniqueProcessId;
665
                    p.tCreation=ftCreation;
666
                    p.tCpu=Time((ftKernel+ftUser)/10000);
667
                    arPinfo.push_back(p);
668
                  }
669
 
670
                  CloseHandle(hProcess);
671
 
672
                }
673
              }
674
            }
675
            delete [] arPids;
676
          }
677
        }
678
      }
679
    }
680
    break;
681
  case VER_PLATFORM_WIN32_WINDOWS:
682
 
683
    if( hInstLib1) {
684
 
685
      static HANDLE (WINAPI *lpfCreateToolhelp32Snapshot)(DWORD,DWORD)=
686
        (HANDLE(WINAPI *)(DWORD,DWORD))GetProcAddress( hInstLib1,"CreateToolhelp32Snapshot" ) ;
687
      static BOOL (WINAPI *lpfProcess32First)(HANDLE,LPPROCESSENTRY32)=
688
        (BOOL(WINAPI *)(HANDLE,LPPROCESSENTRY32))GetProcAddress( hInstLib1, "Process32First" ) ;
689
      static BOOL (WINAPI *lpfProcess32Next)(HANDLE,LPPROCESSENTRY32)=
690
        (BOOL(WINAPI *)(HANDLE,LPPROCESSENTRY32))GetProcAddress( hInstLib1, "Process32Next" ) ;
691
      if( lpfProcess32Next && lpfProcess32First && lpfCreateToolhelp32Snapshot) {
692
 
693
        // Get a handle to a Toolhelp snapshot of the systems
694
        // processes.
695
        HANDLE hSnapShot = lpfCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) ;
696
        if(INVALID_HANDLE_VALUE != hSnapShot) {
697
          // Get the first process' information.
698
          PROCESSENTRY32 procentry;
699
          procentry.dwSize = sizeof(PROCESSENTRY32) ;
700
          if(lpfProcess32First( hSnapShot, &procentry )){
701
            rc=true;
702
            do {
703
              PInfo p;
704
              p.PID=procentry.th32ProcessID;
705
              p.PPID=procentry.th32ParentProcessID;
706
              arPinfo.push_back(p);
707
            } while(lpfProcess32Next( hSnapShot, &procentry ));
708
          }
709
          CloseHandle(hSnapShot);
710
        }
711
      }
712
    }
713
    break;
714
  default:
715
    break;
716
  }
717
 
718
  SetParents(arPinfo);
719
 
720
  if(!rc){
721
    ERROR(_T("Couldn't get process information!\n"));
722
  }
723
  return rc;
724
}
725
 
726
#else // UNIX
727
 
728
bool CSubprocess::PSExtract(CSubprocess::PInfoArray &arPinfo)
729
{
730
  arPinfo.clear();
731
  int i;
732
  FILE *f=popen("ps -l",_T("r") MODE_TEXT);
733
  if(f){
734
    char buf[100];
735
    while(fgets(buf,sizeof(buf)-1,f)){
736
      TCHAR discard[100];
737
      PInfo p;
738
      // Output is in the form
739
      //  F S   UID   PID  PPID  C PRI  NI ADDR    SZ WCHAN  TTY          TIME CMD
740
      //100 S   490   877   876  0  70   0    -   368 wait4  pts/0    00:00:00 bash
741
      int F,UID,C,PRI,NI,SZ,HH,MM,SS;
742
      bool rc=(15==_stscanf(buf,_T("%d %s %d %d %d %d %d %d %s %d %s %s %d:%d:%d"),&F,discard,&UID,&p.PID,&p.PPID,&C,&PRI,&NI,discard,&SZ,discard,discard,&HH,&MM,&SS));
743
      if(rc){
744
        p.tCpu=1000*(SS+60*(60*HH+MM));
745
        arPinfo.push_back(p);
746
      }
747
    }
748
    pclose(f);
749
    for(i=0;i<(signed)arPinfo.size();i++){
750
      int pid=arPinfo[i].PPID;
751
      arPinfo[i].pParent=0;
752
      for(int j=0;j<(signed)arPinfo.size();j++){
753
        if(i!=j && arPinfo[j].PID==pid){
754
          arPinfo[i].pParent=&arPinfo[j];
755
          break;
756
        }
757
      }
758
    }
759
  } else {
760
    ERROR(_T("Failed to run ps -l\n"));
761
  }
762
  return true; //FIXME
763
}
764
 
765
#endif
766
 
767
void CSubprocess::SetParents(CSubprocess::PInfoArray &arPinfo)
768
{
769
  int i;
770
  for(i=0;i<(signed)arPinfo.size();i++){
771
    PInfo &p=arPinfo[i];
772
    p.pParent=0;
773
    for(int j=0;j<(signed)arPinfo.size();j++){
774
      if(arPinfo[j].PID==p.PPID
775
#ifdef _WIN32
776
        && arPinfo[j].tCreation<p.tCreation
777
#endif
778
        )
779
      {
780
        arPinfo[i].pParent=&arPinfo[j];
781
        break;
782
      }
783
    }
784
  }
785
 
786
  // Check for circularity
787
  bool bCircularity=false;
788
  for(i=0;i<(signed)arPinfo.size();i++){
789
    PInfo *p=&arPinfo[i];
790
    for(int j=0;j<(signed)arPinfo.size() && p;j++){
791
      p=p->pParent;
792
    }
793
    // If all is well, p should be NULL here.  Otherwise we have a loop.
794
    if(p){
795
      // Make sure it can't foul things up:
796
      arPinfo[i].pParent=0;
797
      bCircularity=true;
798
    }
799
  }
800
 
801
  if(bCircularity){
802
    ERROR(_T("!!! Circularly linked process list at index %d\n"),i);
803
    for(int k=0;k<(signed)arPinfo.size();k++){
804
      const PInfo &p=arPinfo[k];
805
      ERROR(_T("%d: %s ppid=%4d\n"),k,(LPCTSTR)Name(p.PID),p.PPID);
806
    }
807
  }
808
}
809
 
810
bool CSubprocess::PInfo::IsChildOf(int pid) const
811
{
812
  for(PInfo *p=pParent;p && p!=this;p=p->pParent) { // guard against circular linkage
813
    if(p->PID==pid){
814
      return true;
815
    }
816
  }
817
  return false;
818
}
819
 
820
const String CSubprocess::Name(int pid)
821
{
822
  String str(String::SFormat(_T("id=%d"),pid));
823
#ifdef _DEBUG
824
#ifdef _WIN32
825
  if(VER_PLATFORM_WIN32_NT==GetPlatform() && hInstLib1){
826
    static BOOL (WINAPI *lpfEnumProcessModules)( HANDLE, HMODULE *, DWORD, LPDWORD ) =
827
      (BOOL(WINAPI *)(HANDLE, HMODULE *, DWORD, LPDWORD)) GetProcAddress( hInstLib1,"EnumProcessModules" ) ;
828
    static DWORD (WINAPI *lpfGetModuleFileNameEx)( HANDLE, HMODULE, LPTSTR, DWORD )=
829
      (DWORD (WINAPI *)(HANDLE, HMODULE,LPTSTR, DWORD )) GetProcAddress( hInstLib1,"GetModuleFileNameExA" ) ;
830
    if( lpfEnumProcessModules &&  lpfGetModuleFileNameEx ) {
831
      HANDLE hProcess=::OpenProcess(PROCESS_ALL_ACCESS,false,pid);
832
      if(hProcess) {
833
        HMODULE hMod;
834
        DWORD dwSize;
835
        if(lpfEnumProcessModules( hProcess, &hMod, sizeof(HMODULE), &dwSize ) ){
836
          // Get Full pathname:
837
          TCHAR buf[1+MAX_PATH];
838
          lpfGetModuleFileNameEx( hProcess, hMod, buf, MAX_PATH);
839
          str+=_TCHAR(' ');
840
          str+=buf;
841
        }
842
        CloseHandle(hProcess);
843
      }
844
    }
845
  }
846
#endif
847
#endif
848
  return str;
849
}
850
 
851
#ifdef _WIN32
852
DWORD CSubprocess::GetPlatform()
853
{
854
  OSVERSIONINFO  osver;
855
  osver.dwOSVersionInfoSize = sizeof( osver ) ;
856
  return GetVersionEx( &osver ) ? osver.dwPlatformId : (DWORD)-1;
857
}
858
#endif
859
 
860
bool CSubprocess::ProcessAlive()
861
{
862
  return !m_bThreadTerminated;
863
}
864
 
865
void CSubprocess::CloseInput()
866
{
867
#ifdef _WIN32
868
  CloseHandle(m_hwPipe);m_hwPipe=INVALID_HANDLE_VALUE;
869
#else
870
  close(m_tty);
871
#endif
872
}
873
 
874
bool CSubprocess::Wait(Duration dTimeout)
875
{
876
  return CeCosThreadUtils::WaitFor(m_bThreadTerminated,dTimeout);
877
}
878
 
879
const String CSubprocess::ErrorString() const
880
{
881
#ifdef _WIN32
882
  TCHAR *pszMsg;
883
  FormatMessage(
884
    FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
885
    NULL,
886
    m_nErr,
887
    MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
888
    (LPTSTR)&pszMsg,
889
    0,
890
    NULL
891
    );
892
  return pszMsg;
893
#else 
894
  return strerror(errno);
895
#endif
896
}
897
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.