Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

A Case Study about InterProcess Synchronization

0.00/5 (No votes)
5 Jan 2001 1  
An application demonstrating process synchronisation and interprocess communication
  • Download demo project - 142 Kb
  • Download demo executable - 320 Kb
  • Introduction

    When this new website emerged - a wonderful initiative - I decided to endorse it by writing a 'small' sample project which tries to answer a lot of the issues raised concerning interprocess communication. Later on, more and more functionality was added until you see something like IPS is today.

    The Interprocess Communication

    It will show you

    • How to start a child process with a CreateProcess call (based on Joseph M. Newcomer�s code where I removed the resource leak).
    • How to synchronize (= in this case "wait for a process to end") with the Process Handle.
    • How to �try� to end a process cleanly, (If that does not help, shoot the perpetrator down).
    • How to create a Frame Window with a threaded framework solution for watching processes.

    Except for some advanced features concerning process information retrieval that is obtained from calling UNDOCUMENTED APIs and reading from the NT/W2K system table, most things are quite simple with regard to interprocess synchronization.

    The findings or 'techniques' we demonstrate in this article are based on work done by Sven B. Schreiber, and was published comprehensively in the Dr. Dobb's Journal #305 of November 1999 [ (c) 1999 Miller Freeman, Inc., San Francisco (CA) ]. (www.ddj.com).

    A few C functions to retrieve process information in an OS independent (only MS OS-es were implied here) way are implemented in the "Win32Ext" files. The more interesting ones are:

    • DWORD WINAPI GetProcessModuleName(DWORD dwProcessId, PWORD p_UnicodeString, DWORD dwMaxLength);
    • DWORD WINAPI GetParentProcessId(DWORD dwProcessId, PDWORD p_dwParentPId);
    • DWORD WINAPI GetChildProcesses (DWORD dwProcessId, PDWORD p_dwChildPIds, DWORD dwMaxLength, PDWORD p_dwNrChildren);
    • DWORD WINAPI GetNumberOfProcesses(PDWORD p_dwNrProcesses);
    • DWORD WINAPI GetProcessCommitCharge(DWORD dwProcessId, PDWORD p_dwCommitCharge);
    • DWORD WINAPI GetProcessUserTime(DWORD dwProcessId, PLARGE_INTEGER p_UserTime);
    • DWORD WINAPI GetProcessKernelTime(DWORD dwProcessId, PLARGE_INTEGER p_KernelTime);
    • DWORD WINAPI GetProcessThreadIds(DWORD dwProcessId, PDWORD p_dwThreadIds, DWORD dwMaxLength, PDWORD p_dwNrThreads);
    • DWORD WINAPI GetProcessCreationTime DWORD dwProcessId, PSYSTEMTIME p_SystemTime);
    • DWORD WINAPI GetProcessBasePriority(DWORD dwProcessId, PDWORD p_dwBasePriority);

    Interprocess communication through message dispatching (e.g. used to politely request an application to stop) is done by posting messages to the process windows and was based on code published by Martin-Pierre Frenette. (Sending a message to the Main Frame Window of Another Application, given only the Process Handle).

    You will also notice that some programs do NOT FOLLOW the standard Parent - Child Process rules: If you would start "Explorer.exe" from within "IPS.exe", you will see that the explorer process is NOT a child of IPS.

    The Process Object and Process Debugger Object

    I rewrote the original IPS code to have somewhat more structure (Let�s face it, it was poor C++, and even now� ). So I came up with the ProcessObject class. It provides an easy way to most things you ever wanted to do with a process. Functions are available to launch and terminate a process, to change its base priority, to send it a message (if it has a window), �

    Also, � you can attach to the target process as a debugger by using a ProcessDebugger Object.

    The Process Debugger is notified of the following events through a C++ call-back mechanism: �����

    void OnException(DebugEvent_Exception* pDE);
    void OnProcessStart(DebugEvent_Process* pDE);
    void OnProcessExit(DebugEvent_Process* pDE);
    void OnThreadStart(DebugEvent_Thread* pDE);
    void OnThreadExit(DebugEvent_Thread* pDE);
    void OnDllLoad(DebugEvent_DLL* pDE);
    void OnDllUnload(DebugEvent_DLL* pDE);
    void OnDebugOutput(DebugEvent_Output* pDE);
    

    The respective pointers to the DebugEvent objects provide all the necessary information during the events. Getting the Debug functions to work can be error prone, so if you want a simplified idea of how the VC Debugger does it, check it out.

    The ProcessDebugger also has a nifty Thread Stack Dumper Object (through aggregation), which can come in handy if you want to know the exact context of an exception for example. I found my sample of stack dumping functionality at Felix Kaska�s Win32 Pages ( http://mvps.org/win32/ ). I (almost completely) rewrote the functionality and put it in the respective StackFrame and ThreadFunctionStack classes. It provides functionality to dump the stack of a thread inside its own process, possibly as a reaction to an exception (but not only at that time), and it is also possible to dump the stack of a thread in another process (if you have the necessary DEBUG privileges, of course). The debug symbols, if available, are only loaded when needed. It�s up to the software engineer to decide whether he or she wants to put a minimal amount of debug information into the executable. If a �.map� file was built (in the link step), the information provided by the stack dump in combination with the map file should be sufficient to figure out the function context even when no debug information is included in the executable. (Read MSDN if you are not sure how to add and choose the type of debug information). If more debug symbol information (besides registers and instruction pointers) is available in the executable, it will be used (by IPS through the ImageHlp dll) and logged which makes it a lot easier to figure out what went wrong.

    Tracing

    For internal bug tracking IPS uses the TraceLogger class, which can log or trace functions (and function returns), errors and unhandled exceptions to a log file. By using macros we can put extra information in the log file to make our debugging tasks in the field easier. If required, the log file can be split up into separate parts (for file usage rotation purposes, so the maximum file size used by the logger is limited), which could be encrypted using for example a CryptLib or an in-house developed stream encryption algorithm. IPS does not encrypt the log file because the source is there for everyone to see. If an unhandled exception occurs, naturally IPS will stack dump its own offending thread before terminating. (If you would be so kind as to send the log file to me if that happens.)

    The Trace Level can be adjusted at run-time (see the IPS about box).

    You could also remove some of the function tracing by redefining the macros to empty statements (and recompiling the Application) :

    LOGTRACE(l, s) 
    LOGTRACEFUNC(s)
    LOGTRACEERROR(e, s)
    LOGTRACEFUNCRETURN(e, s)
    LOGTRACEDUMPSTACK()
    LOGTRACEOSTREAM(s)
    LOGTRACEPROGRESSWITHOSTREAM() 

    Live Debug Output Window

    For Logging the debug event, I used a slightly modified version of TOutputWnd made by Ben Ashley. The original version can be found at CodeGuru ( www.codeguru.com ). The IPS user can dump the log file in text format, which can be used to point the support department or developer of the crashed program to the offending code. (Doh!)

    Future Enchancements

    System wide Hooking of the CreateProcess (and CreateThread) calls to improve performance instead of using a dumb timer.

    Just wondering whether it is necessary to dump all the threads on a program crash�

    Provide real UNICODE compliant code.

    Other (Any suggestions?)

    Note on the Compiler Used

    I used an evaluation version of the Intel 5.0 Compiler, which produces (much bigger) faster and automatically optimised code for the Intel PI/PII/PIII family. It integrates seamlessly in the MS VC Development environment and is fully (?) compatible with the MS VC Compiler.

    Gert Boddaert, Alias GBO.

    License

    This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

    A list of licenses authors might use can be found here