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

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [tools/] [src/] [tools/] [Utils/] [common/] [Subprocess.cpp] - Blame information for rev 174

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

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