~ubuntu-branches/ubuntu/quantal/zeroc-ice/quantal

« back to all changes in this revision

Viewing changes to cpp/src/IceGrid/Activator.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Cleto Martin Angelina
  • Date: 2011-04-25 18:44:24 UTC
  • mfrom: (6.1.14 sid)
  • Revision ID: james.westby@ubuntu.com-20110425184424-sep9i9euu434vq4c
Tags: 3.4.1-7
* Bug fix: "libdb5.1-java.jar was renamed to db.jar", thanks to Ondřej
  Surý (Closes: #623555).
* Bug fix: "causes noise in php5", thanks to Jayen Ashar (Closes:
  #623533).

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
// **********************************************************************
2
2
//
3
 
// Copyright (c) 2003-2009 ZeroC, Inc. All rights reserved.
 
3
// Copyright (c) 2003-2010 ZeroC, Inc. All rights reserved.
4
4
//
5
5
// This copy of Ice is licensed to you under the terms described in the
6
6
// ICE_LICENSE file included in this distribution.
29
29
#   include <sys/wait.h>
30
30
#   include <signal.h>
31
31
#else
32
 
#   include <direct.h> // For _getcwd
33
32
#ifndef SIGKILL
34
33
#   define SIGKILL 9
35
34
#endif
40
39
 
41
40
using namespace std;
42
41
using namespace Ice;
 
42
using namespace IceInternal;
43
43
using namespace IceGrid;
44
44
 
 
45
#define ICE_STRING(X) #X
 
46
 
45
47
namespace IceGrid
46
48
{
47
49
 
50
52
public:
51
53
 
52
54
    TerminationListenerThread(Activator& activator) :
 
55
        IceUtil::Thread("IceGrid termination listener thread"),
53
56
        _activator(activator)
54
57
    {
55
58
    }
65
68
    Activator& _activator;
66
69
};
67
70
 
68
 
}
69
 
 
70
 
#define ICE_STRING(X) #X
71
 
 
72
 
namespace IceGrid
73
 
{
74
 
 
75
71
#ifndef _WIN32
76
72
//
77
73
// Helper function for async-signal safe error reporting
266
262
    }
267
263
}
268
264
 
 
265
#ifdef _WIN32
 
266
struct UnicodeStringLess
 
267
{
 
268
 
 
269
bool
 
270
operator()(const wstring& lhs, const wstring& rhs) const
 
271
{
 
272
    int r = CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, lhs.c_str(), -1, rhs.c_str(), -1);
 
273
    assert(r > 0);
 
274
    return r == CSTR_LESS_THAN;
 
275
}
 
276
 
 
277
};
 
278
#endif
 
279
 
269
280
}
270
281
 
271
282
Activator::Activator(const TraceLevelsPtr& traceLevels) :
353
364
            //
354
365
            // Get the absolute pathname of the executable.
355
366
            //
356
 
            char absbuf[_MAX_PATH];
357
 
            char* filePart;
358
 
            string ext = path.size() <= 4 || path[path.size() - 4] != '.' ? ".exe" : "";
359
 
            if(SearchPath(NULL, path.c_str(), ext.c_str(), _MAX_PATH, absbuf, &filePart) == 0)
 
367
            wchar_t absbuf[_MAX_PATH];
 
368
            wchar_t* fPart;
 
369
            wstring ext = path.size() <= 4 || path[path.size() - 4] != '.' ? L".exe" : L"";
 
370
            if(SearchPathW(NULL, IceUtil::stringToWstring(path).c_str(), ext.c_str(), _MAX_PATH, absbuf, &fPart) == 0)
360
371
            {
361
372
                if(_traceLevels->activator > 0)
362
373
                {
365
376
                }
366
377
                throw string("Couldn't find `" + path + "' executable.");
367
378
            }
368
 
            path = absbuf;
 
379
            path = IceUtil::wstringToString(absbuf);
369
380
        }
370
381
        else if(!pwd.empty())
371
382
        {
378
389
    //
379
390
    if(!pwd.empty())
380
391
    {
381
 
        char absbuf[_MAX_PATH];
382
 
        if(_fullpath(absbuf, pwd.c_str(), _MAX_PATH) == NULL)
 
392
        wchar_t absbuf[_MAX_PATH];
 
393
        if(_wfullpath(absbuf, IceUtil::stringToWstring(pwd).c_str(), _MAX_PATH) == NULL)
383
394
        {
384
395
            if(_traceLevels->activator > 0)
385
396
            {
388
399
            }
389
400
            throw string("The server working directory path `" + pwd + "' can't be converted into an absolute path.");
390
401
        }
391
 
        pwd = absbuf;
 
402
        pwd = IceUtil::wstringToString(absbuf);
392
403
    }
393
404
#endif
394
405
 
398
409
    StringSeq args;
399
410
    args.push_back(path);
400
411
    args.insert(args.end(), options.begin(), options.end());
401
 
    
 
412
 
402
413
    if(_traceLevels->activator > 0)
403
414
    {
404
415
        Ice::Trace out(_traceLevels->logger, _traceLevels->activatorCat);
409
420
            out << "path = " << path << "\n";
410
421
            if(pwd.empty())
411
422
            {
412
 
#ifdef _WIN32
413
 
                char cwd[_MAX_PATH];
414
 
                if(_getcwd(cwd, _MAX_PATH) != NULL)
415
 
#else
416
 
                char cwd[PATH_MAX];
417
 
                if(getcwd(cwd, PATH_MAX) != NULL)
418
 
#endif
 
423
                string cwd;
 
424
                if(IceUtilInternal::getcwd(cwd) == 0)
419
425
                {
420
 
                    out << "pwd = " << string(cwd) << "\n";
 
426
                    out << "pwd = " << cwd << "\n";
421
427
                }
422
428
            }
423
429
            else
469
475
        }
470
476
    }
471
477
 
472
 
    const char* dir;
473
 
    if(!pwd.empty())
474
 
    {
475
 
        dir = pwd.c_str();
476
 
    }
477
 
    else
478
 
    {
479
 
        dir = NULL;
480
 
    }
 
478
    wstring wpwd = IceUtil::stringToWstring(pwd);
 
479
    const wchar_t* dir = !wpwd.empty() ? wpwd.c_str() : NULL;
481
480
 
482
481
    //
483
482
    // Make a copy of the command line.
484
483
    //
485
484
#if defined(_MSC_VER) && (_MSC_VER >= 1400)
486
 
    char* cmdbuf = _strdup(cmd.c_str());
 
485
    wchar_t* cmdbuf = _wcsdup(IceUtil::stringToWstring(cmd).c_str());
487
486
#else
488
 
    char* cmdbuf = strdup(cmd.c_str());
 
487
    wchar_t* cmdbuf = wcsdup(IceUtil::stringToWstring(cmd).c_str());
489
488
#endif
490
489
 
491
490
    //
494
493
    // Since Windows is case insensitive wrt environment variables we convert the keys to
495
494
    // uppercase to ensure matches are found.
496
495
    //
497
 
    const char* env = NULL;
498
 
    string envbuf;
 
496
    const wchar_t* env = NULL;
 
497
    wstring envbuf;
499
498
    if(!envs.empty())
500
499
    {
501
 
        map<string, string> envMap;
502
 
        LPVOID parentEnv = GetEnvironmentStrings();
503
 
        const char* var = reinterpret_cast<const char*>(parentEnv);
504
 
        if(*var == '=')
 
500
        map<wstring, wstring, UnicodeStringLess> envMap;
 
501
        LPVOID parentEnv = GetEnvironmentStringsW();
 
502
        const wchar_t* var = reinterpret_cast<const wchar_t*>(parentEnv);
 
503
        if(*var == L'=')
505
504
        {
506
505
            //
507
506
            // The environment block may start with some information about the
508
507
            // current drive and working directory. This is indicated by a leading
509
508
            // '=' character, so we skip to the first '\0' byte.
510
509
            //
511
 
            while(*var)
 
510
            while(*var != L'\0')
512
511
                var++;
513
512
            var++;
514
513
        }
515
 
        while(*var)
 
514
        while(*var != L'\0')
516
515
        {
517
 
            string s(var);
518
 
            string::size_type pos = s.find('=');
519
 
            if(pos != string::npos)
 
516
            wstring s(var);
 
517
            wstring::size_type pos = s.find(L'=');
 
518
            if(pos != wstring::npos)
520
519
            {
521
 
                string key = IceUtilInternal::toUpper(s.substr(0, pos));
522
 
                envMap.insert(map<string, string>::value_type(key, s.substr(pos + 1)));
 
520
                envMap[s.substr(0, pos)] = s.substr(pos + 1);
523
521
            }
524
522
            var += s.size();
525
523
            var++; // Skip the '\0' byte
526
524
        }
527
 
        FreeEnvironmentStrings(static_cast<char*>(parentEnv));
 
525
        FreeEnvironmentStringsW(static_cast<wchar_t*>(parentEnv));
528
526
        for(p = envs.begin(); p != envs.end(); ++p)
529
527
        {
530
 
            string s = *p;
531
 
            string::size_type pos = s.find('=');
532
 
            if(pos != string::npos)
 
528
            wstring s = IceUtil::stringToWstring(*p);
 
529
            wstring::size_type pos = s.find(L'=');
 
530
            if(pos != wstring::npos)
533
531
            {
534
 
                string key = IceUtilInternal::toUpper(s.substr(0, pos));
535
 
                envMap.erase(key);
536
 
                envMap.insert(map<string, string>::value_type(key, s.substr(pos + 1)));
 
532
                envMap[s.substr(0, pos)] = s.substr(pos + 1);
537
533
            }
538
534
        }
539
 
        for(map<string, string>::const_iterator q = envMap.begin(); q != envMap.end(); ++q)
 
535
 
 
536
        for(map<wstring, wstring, UnicodeStringLess>::const_iterator q = envMap.begin(); q != envMap.end(); ++q)
540
537
        {
541
538
            envbuf.append(q->first);
542
 
            envbuf.push_back('=');
 
539
            envbuf.push_back(L'=');
543
540
            envbuf.append(q->second);
544
 
            envbuf.push_back('\0');
 
541
            envbuf.push_back(L'\0');
545
542
        }
546
 
        envbuf.push_back('\0');
 
543
        envbuf.push_back(L'\0');
547
544
        env = envbuf.c_str();
548
545
    }
549
546
 
550
547
    Process process;
551
548
 
552
 
    STARTUPINFO si;
 
549
    STARTUPINFOW si;
553
550
    ZeroMemory(&si, sizeof(si));
554
551
    si.cb = sizeof(si);
555
552
    
556
553
    PROCESS_INFORMATION pi;
557
554
    ZeroMemory(&pi, sizeof(pi));
558
 
 
559
 
    BOOL b = CreateProcess(
 
555
    BOOL b = CreateProcessW(
560
556
        NULL,                     // Executable
561
557
        cmdbuf,                   // Command line
562
558
        NULL,                     // Process attributes
563
559
        NULL,                     // Thread attributes
564
560
        FALSE,                    // Do NOT inherit handles
565
 
        CREATE_NEW_PROCESS_GROUP, // Process creation flags
 
561
        CREATE_NEW_PROCESS_GROUP | CREATE_UNICODE_ENVIRONMENT, // Process creation flags
566
562
        (LPVOID)env,              // Process environment
567
563
        dir,                      // Current directory
568
564
        &si,                      // Startup info
581
577
    // keep the thread handle, so we close it now. The process handle will be closed later.
582
578
    //
583
579
    CloseHandle(pi.hThread);
584
 
 
585
580
    
586
581
    process.pid = pi.dwProcessId;
587
582
    process.hnd = pi.hProcess;
1376
1371
int
1377
1372
Activator::waitPid(pid_t processPid)
1378
1373
{
1379
 
    int status;
 
1374
    try
 
1375
    {
 
1376
        int status;
1380
1377
#if defined(__linux)
1381
 
    int nRetry = 0;
1382
 
    while(true) // The while loop is necessary for the linux workaround.
1383
 
    {
 
1378
        int nRetry = 0;
 
1379
        while(true) // The while loop is necessary for the linux workaround.
 
1380
        {
 
1381
            pid_t pid = waitpid(processPid, &status, 0);
 
1382
            if(pid < 0)
 
1383
            {
 
1384
                //
 
1385
                // Some Linux distribution have a bogus waitpid() (e.g.: CentOS 4.x). It doesn't 
 
1386
                // block and reports an incorrect ECHILD error on the first call. We sleep a 
 
1387
                // little and retry to work around this issue (it appears from testing that a
 
1388
                // single retry is enough but to make sure we retry up to 10 times before to throw.)
 
1389
                //
 
1390
                if(errno == ECHILD && nRetry < 10)
 
1391
                {
 
1392
                    // Wait 1ms, 11ms, 21ms, etc.
 
1393
                    IceUtil::ThreadControl::sleep(IceUtil::Time::milliSeconds(nRetry * 10 + 1)); 
 
1394
                    ++nRetry;
 
1395
                    continue;
 
1396
                }
 
1397
                SyscallException ex(__FILE__, __LINE__);
 
1398
                ex.error = getSystemErrno();
 
1399
                throw ex;
 
1400
            }
 
1401
            assert(pid == processPid);
 
1402
            break;
 
1403
        }
 
1404
#else
1384
1405
        pid_t pid = waitpid(processPid, &status, 0);
1385
1406
        if(pid < 0)
1386
1407
        {
1387
 
            //
1388
 
            // Some Linux distribution have a bogus waitpid() (e.g.: CentOS 4.x). It doesn't 
1389
 
            // block and reports an incorrect ECHILD error on the first call. We sleep a 
1390
 
            // little and retry to work around this issue (it appears from testing that a
1391
 
            // single retry is enough but to make sure we retry up to 10 times before to throw.)
1392
 
            //
1393
 
            if(errno == ECHILD && nRetry < 10)
1394
 
            {
1395
 
                // Wait 1ms, 11ms, 21ms, etc.
1396
 
                IceUtil::ThreadControl::sleep(IceUtil::Time::milliSeconds(nRetry * 10 + 1)); 
1397
 
                ++nRetry;
1398
 
                continue;
1399
 
            }
1400
1408
            SyscallException ex(__FILE__, __LINE__);
1401
1409
            ex.error = getSystemErrno();
1402
1410
            throw ex;
1403
1411
        }
1404
1412
        assert(pid == processPid);
1405
 
        break;
 
1413
#endif
 
1414
        return status;
1406
1415
    }
1407
 
#else
1408
 
    pid_t pid = waitpid(processPid, &status, 0);
1409
 
    if(pid < 0)
 
1416
    catch(const Ice::LocalException& ex)
1410
1417
    {
1411
 
        SyscallException ex(__FILE__, __LINE__);
1412
 
        ex.error = getSystemErrno();
1413
 
        throw ex;
 
1418
        Error out(_traceLevels->logger);
 
1419
        out << "unable to get process status:\n" << ex;
 
1420
        return -1;
1414
1421
    }
1415
 
    assert(pid == processPid);
1416
 
#endif
1417
 
    return status;
1418
1422
}
1419
1423
#endif