0

Processes and IPC in BrowserPlus

Yesterday at add-on-con I spoke with Lloyd Hilaiel about the multi-process and IPC architecture in BrowserPlus. I found this architecture very interesting and would like to learn more about starting and stopping the process and ensuring there is only one process. In addition I'd love more details on the IPC mechanism used on both Win32 and OSX.

Thanks!
Marcus

by
4 Replies
  • QUOTE (marcus_irven @ Dec 12 2008, 10:42 AM) <{POST_SNAPBACK}>
    Yesterday at add-on-con I spoke with Lloyd Hilaiel about the multi-process and IPC architecture in BrowserPlus. I found this architecture very interesting and would like to learn more about starting and stopping the process and ensuring there is only one process. In addition I'd love more details on the IPC mechanism used on both Win32 and OSX.

    Thanks!
    Marcus


    Hey Marcus, thanks for posting ;)lloyd
    0
  • Thanks Lloyd! I'm sure I'll more questions once I get into this and I look forward to the open-source code.
    0
  • Can you tell me a little more about how you start the process? We have the beginnings of a proof of concept working on OSX using fork() is this what you are using? And what about Windows, there is CreateProcess() but it is unclear at this point on how it is used exactly without having a separate .exe used for the daemon.

    Thanks,
    Marcus
    0
  • QUOTE (marcus_irven @ Feb 12 2009, 01:47 PM) <{POST_SNAPBACK}>
    Can you tell me a little more about how you start the process? We have the beginnings of a proof of concept working on OSX using fork() is this what you are using? And what about Windows, there is CreateProcess() but it is unclear at this point on how it is used exactly without having a separate .exe used for the daemon.

    Thanks,
    Marcus


    hey marcus, glad to hear from you again! something like this on windows:
    CODE
    static bool 
    invokeCreateProcess(const string& sPath,
    const std::string& sTitle, // XXX: must figure out how to change process name!
    const std::string& workingDirectory,
    const vector<string>& vsArgs,
    bp::process::spawnStatus* pStat,
    bool elevate,
    bool showWindow)
    {
    std::wstring wWorkDir;
    if (!workingDirectory.empty()) {
    wWorkDir = bp::strutil::utf8ToWide(workingDirectory);
    }
    // get path and args into writable C buf needed by ShellExecuteEx()
    const int nBUFLEN = 1024;
    wchar_t szCommandLine[nBUFLEN];
    std::wstring wsPath = bp::strutil::utf8ToWide(sPath);
    memcpy((void *) szCommandLine, (void *) wsPath.c_str(),
    wsPath.length() * sizeof(wchar_t));
    szCommandLine[wsPath.length()] = 0;

    wchar_t szArgs[nBUFLEN];
    memset(&szArgs, 0, nBUFLEN);
    if (vsArgs.size() > 0) {
    std::wstring wsArgs = redmondParameterEscape(vsArgs);
    memcpy((void *) szArgs, (void *) wsArgs.c_str(),
    wsArgs.length() * sizeof(wchar_t));
    szArgs[wsArgs.length()] = 0;
    }

    // now execute sPath with args, elevated on Vista if needed
    SHELLEXECUTEINFOW shex;
    ZeroMemory(&shex, sizeof(shex));
    shex.cbSize = sizeof(SHELLEXECUTEINFO);
    shex.fMask = SEE_MASK_NOCLOSEPROCESS|SEE_MASK_FLAG_NO_UI;
    shex.hwnd = NULL;
    string osVersion = bp::os::PlatformVersion();
    bool isVista = osVersion.compare("6.") >= 0;
    std::wstring wVerb;
    if (isVista && elevate) wVerb = bp::strutil::utf8ToWide("runas");
    shex.lpVerb = (wVerb.empty()) ? NULL : wVerb.c_str();
    shex.lpFile = szCommandLine;
    shex.lpParameters = szArgs;
    shex.lpDirectory = NULL;
    if (!wWorkDir.empty()) shex.lpDirectory = wWorkDir.c_str();
    shex.nShow = showWindow ? SW_SHOWNORMAL : SW_HIDE;
    bool bRet = ShellExecuteExW(&shex);

    if (bRet) {
    if (pStat) {
    pStat->errCode = 0;
    pStat->pid = GetProcessId(shex.hProcess);
    pStat->handle = shex.hProcess;
    }
    } else {
    if (pStat) {
    pStat->errCode = GetLastError();
    pStat->pid = 0;
    }
    }
    return (bRet!=0);
    }


    And something like this on unix:

    CODE
    bool forkAndExec(const std::string & path, const std::string & pwd,
    char *const argv[], bp::process::spawnStatus* pStat)
    {
    pid_t pid = fork();
    if (pid == 0)
    {
    // if a pwd is provided, now is the time to chdir
    if (!pwd.empty() && 0 != chdir(pwd.c_str())) {
    // TODO: we need a good way to return error!
    // a convention around return codes??
    std::cerr << "failed to chdir()" << std::endl;
    exit(1);
    }

    // We're the child. Now execute the desired image.
    int nRet = execv(path.c_str(), argv);
    if (nRet == -1)
    {
    // TODO: perhaps notify parent of child execve failure.
    exit(1);
    }

    // return is basically irrelevant in this case.
    return true;
    }
    else if (pid == -1)
    {
    // We're the parent and fork failed.
    if (pStat)
    {
    pStat->errCode = errno;
    pStat->pid = 0;
    }

    return false;
    }
    else
    {
    // We're the parent and fork succeeded.
    if (pStat)
    {
    pStat->errCode = 0;
    pStat->pid = pid;
    }

    return true;
    }
    }


    As far as your comment about a separate exe, afaik this is a requirement on windows, and on osx with so many frameworks that use process global resources, you can't reliably do anything without an exec. For us we mitigate the distribution hit of shipping multiple different binaries by having a single binary that can run in different modes, and we make copies of that binary at install time for niceties such as resonably discoverable process names in activity monitor or task manager...

    hth! can't wait till I can point you at github rather than copying and pasting.

    very best,
    lloyd
    0
This forum is locked.

Recent Posts

in Support & General Questions